blob: 8df8da54821b1e383accc13605e3505af1e82f3e [file] [log] [blame]
initial.commit09911bf2008-07-26 23:55:291// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "chrome/views/view.h"
31
32#include <algorithm>
33#include <sstream>
34#include <iostream>
35
36#include "base/logging.h"
37#include "base/message_loop.h"
38#include "base/string_util.h"
39#include "chrome/common/gfx/chrome_canvas.h"
40#include "chrome/common/os_exchange_data.h"
41#include "chrome/views/background.h"
42#include "chrome/views/border.h"
43#include "chrome/views/layout_manager.h"
44#include "chrome/views/root_view.h"
45#include "chrome/views/tooltip_manager.h"
46#include "chrome/views/view_container.h"
47#include "SkShader.h"
48
49namespace ChromeViews {
50
51// static
52char View::kViewClassName[] = "chrome/views/View";
53
54////////////////////////////////////////////////////////////////////////////////
55//
56// A task used to automatically restore focus on the last focused floating view
57//
58////////////////////////////////////////////////////////////////////////////////
59
60class RestoreFocusTask : public Task {
61 public:
62 explicit RestoreFocusTask(View* target) : view_(target) {
63 }
64
65 ~RestoreFocusTask() {}
66
67 void Cancel() {
68 view_ = NULL;
69 }
70
71 void Run() {
72 if (view_)
73 view_->RestoreFloatingViewFocus();
74 }
75 private:
76 // The target view.
77 View* view_;
78
79 DISALLOW_EVIL_CONSTRUCTORS(RestoreFocusTask);
80};
81
82/////////////////////////////////////////////////////////////////////////////
83//
84// View - constructors, destructors, initialization
85//
86/////////////////////////////////////////////////////////////////////////////
87
88View::View()
89 : id_(0),
90 group_(-1),
91 bounds_(0,0,0,0),
92 parent_(NULL),
93 enabled_(true),
94 is_visible_(true),
95 focusable_(false),
96 background_(NULL),
97 accessibility_(NULL),
98 border_(NULL),
99 is_parent_owned_(true),
100 notify_when_visible_bounds_in_root_changes_(false),
101 registered_for_visible_bounds_notification_(false),
102 next_focusable_view_(NULL),
103 previous_focusable_view_(NULL),
104 should_restore_focus_(false),
105 restore_focus_view_task_(NULL),
106 context_menu_controller_(NULL),
107 drag_controller_(NULL),
108 ui_mirroring_is_enabled_for_rtl_languages_(true),
109 flip_canvas_on_paint_for_rtl_ui_(false) {
110}
111
112View::~View() {
113 if (restore_focus_view_task_)
114 restore_focus_view_task_->Cancel();
115
116 int c = static_cast<int>(child_views_.size());
117 while (--c >= 0) {
118 if (child_views_[c]->IsParentOwned())
119 delete child_views_[c];
120 else
121 child_views_[c]->SetParent(NULL);
122 }
123 if (background_)
124 delete background_;
125 if (border_)
126 delete border_;
127}
128
129/////////////////////////////////////////////////////////////////////////////
130//
131// View - sizing
132//
133/////////////////////////////////////////////////////////////////////////////
134
135void View::GetBounds(CRect* out, PositionMirroringSettings settings) const {
136 *out = bounds_;
137
138 // If the parent uses an RTL UI layout and if we are asked to transform the
139 // bounds to their mirrored position if necessary, then we should shift the
140 // rectangle appropriately.
141 if (settings == APPLY_MIRRORING_TRANSFORMATION) {
142 out->MoveToX(MirroredX());
143 }
144}
145
146// GetY(), GetWidth() and GetHeight() are agnostic to the RTL UI layout of the
147// parent view. GetX(), on the other hand, is not.
148int View::GetX(PositionMirroringSettings settings) const {
149 if (settings == IGNORE_MIRRORING_TRANSFORMATION) {
150 return bounds_.left;
151 }
152 return MirroredX();
153}
154
155void View::SetBounds(const CRect& bounds) {
156 if (bounds.left == bounds_.left &&
157 bounds.top == bounds_.top &&
158 bounds.Width() == bounds_.Width() &&
159 bounds.Height() == bounds_.Height()) {
160 return;
161 }
162
163 CRect prev = bounds_;
164 bounds_ = bounds;
165 if (bounds_.right < bounds_.left)
166 bounds_.right = bounds_.left;
167
168 if (bounds_.bottom < bounds_.top)
169 bounds_.bottom = bounds_.top;
170
171 DidChangeBounds(prev, bounds_);
172
173 RootView* root = GetRootView();
174 if (root) {
175 bool size_changed = (prev.Width() != bounds_.Width() ||
176 prev.Height() != bounds_.Height());
177 bool position_changed = (prev.left != bounds_.left ||
178 prev.top != bounds_.top);
179 if (size_changed || position_changed)
180 root->ViewBoundsChanged(this, size_changed, position_changed);
181 }
182}
183
184void View::SetBounds(int x, int y, int width, int height) {
185 CRect tmp(x, y, x + width, y + height);
186 SetBounds(tmp);
187}
188
189void View::GetLocalBounds(CRect* out, bool include_border) const {
190 if (include_border || border_ == NULL) {
191 out->left = 0;
192 out->top = 0;
193 out->right = GetWidth();
194 out->bottom = GetHeight();
195 } else {
196 gfx::Insets insets;
197 border_->GetInsets(&insets);
198 out->left = insets.left();
199 out->top = insets.top();
200 out->right = GetWidth() - insets.left();
201 out->bottom = GetHeight() - insets.top();
202 }
203}
204
205void View::GetSize(CSize* sz) const {
206 sz->cx = GetWidth();
207 sz->cy = GetHeight();
208}
209
210void View::GetPosition(CPoint* p) const {
211 p->x = GetX(APPLY_MIRRORING_TRANSFORMATION);
212 p->y = GetY();
213}
214
215void View::GetPreferredSize(CSize* out) {
216 if (layout_manager_.get()) {
217 layout_manager_->GetPreferredSize(this, out);
218 } else {
219 out->cx = out->cy = 0;
220 }
221}
222
223void View::SizeToPreferredSize() {
224 CSize size;
225 GetPreferredSize(&size);
226 if ((size.cx != GetWidth()) || (size.cy != GetHeight()))
227 SetBounds(GetX(), GetY(), size.cx, size.cy);
228}
229
230void View::GetMinimumSize(CSize* out) {
231 GetPreferredSize(out);
232}
233
234int View::GetHeightForWidth(int w) {
235 if (layout_manager_.get())
236 return layout_manager_->GetPreferredHeightForWidth(this, w);
237
238 CSize size;
239 GetPreferredSize(&size);
240 return size.cy;
241}
242
243void View::DidChangeBounds(const CRect& previous, const CRect& current) {
244}
245
246void View::ScrollRectToVisible(int x, int y, int width, int height) {
247 View* parent = GetParent();
248
249 // We must take RTL UI mirroring into account when adjusting the position of
250 // the region.
251 if (parent)
252 parent->ScrollRectToVisible(
253 GetX(APPLY_MIRRORING_TRANSFORMATION) + x, GetY() + y, width, height);
254}
255
256/////////////////////////////////////////////////////////////////////////////
257//
258// View - layout
259//
260/////////////////////////////////////////////////////////////////////////////
261
262void View::Layout() {
263 // Layout child Views
264 if (layout_manager_.get()) {
265 layout_manager_->Layout(this);
266 SchedulePaint();
267 }
268
269 // Lay out contents of child Views
270 int child_count = GetChildViewCount();
271 for (int i = 0; i < child_count; ++i) {
272 View* child = GetChildViewAt(i);
273 child->Layout();
274 }
275}
276
277LayoutManager* View::GetLayoutManager() const {
278 return layout_manager_.get();
279}
280
281void View::SetLayoutManager(LayoutManager* layout_manager) {
282 if (layout_manager_.get()) {
283 layout_manager_->Uninstalled(this);
284 }
285 layout_manager_.reset(layout_manager);
286 if (layout_manager_.get()) {
287 layout_manager_->Installed(this);
288 }
289}
290
291////////////////////////////////////////////////////////////////////////////////
292//
293// View - Right-to-left UI layout
294//
295////////////////////////////////////////////////////////////////////////////////
296
297inline int View::MirroredX() const {
298 View* parent = GetParent();
299 if (parent && parent->UILayoutIsRightToLeft()) {
300 return parent->GetWidth() - bounds_.left - GetWidth();
301 }
302 return bounds_.left;
303}
304
305int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const {
306 if (!UILayoutIsRightToLeft()) {
307 return bounds.x();
308 }
309 return GetWidth() - bounds.x() - bounds.width();
310}
311
312////////////////////////////////////////////////////////////////////////////////
313//
314// View - states
315//
316////////////////////////////////////////////////////////////////////////////////
317
318bool View::IsEnabled() const {
319 return enabled_;
320}
321
322void View::SetEnabled(bool state) {
323 if (enabled_ != state) {
324 enabled_ = state;
325 SchedulePaint();
326 }
327}
328
329bool View::IsFocusable() const {
330 return focusable_ && enabled_ && is_visible_;
331}
332
333void View::SetFocusable(bool focusable) {
334 focusable_ = focusable;
335}
336
337FocusManager* View::GetFocusManager() {
338 ViewContainer* container = GetViewContainer();
339 if (!container)
340 return NULL;
341
342 HWND hwnd = container->GetHWND();
343 if (!hwnd)
344 return NULL;
345
346 return ChromeViews::FocusManager::GetFocusManager(hwnd);
347}
348
349bool View::HasFocus() {
350 RootView* root_view = GetRootView();
351 FocusManager* focus_manager = GetFocusManager();
352 if (focus_manager)
353 return focus_manager->GetFocusedView() == this;
354 return false;
355}
356
357void View::SetHotTracked(bool flag) {
358}
359
360/////////////////////////////////////////////////////////////////////////////
361//
362// View - painting
363//
364/////////////////////////////////////////////////////////////////////////////
365
366void View::SchedulePaint(const CRect& r, bool urgent) {
367 if (!IsVisible()) {
368 return;
369 }
370
371 if (parent_) {
372 // Translate the requested paint rect to the parent's coordinate system
373 // then pass this notification up to the parent.
374 CRect paint_rect(r);
375 CPoint p;
376 GetPosition(&p);
377 paint_rect.OffsetRect(p);
378 parent_->SchedulePaint(paint_rect, urgent);
379 }
380}
381
382void View::SchedulePaint() {
383 CRect lb;
384 GetLocalBounds(&lb, true);
385 SchedulePaint(lb, false);
386}
387
388void View::SchedulePaint(int x, int y, int w, int h) {
389 CRect r(x, y, x + w, y + h);
390 SchedulePaint(&r, false);
391}
392
393void View::Paint(ChromeCanvas* canvas) {
394 PaintBackground(canvas);
395 PaintFocusBorder(canvas);
396 PaintBorder(canvas);
397}
398
399void View::PaintBackground(ChromeCanvas* canvas) {
400 if (background_)
401 background_->Paint(canvas, this);
402}
403
404void View::PaintBorder(ChromeCanvas* canvas) {
405 if (border_)
406 border_->Paint(*this, canvas);
407}
408
409void View::PaintFocusBorder(ChromeCanvas* canvas) {
410 if (HasFocus() && IsFocusable())
411 canvas->DrawFocusRect(0, 0, GetWidth(), GetHeight());
412}
413
414void View::PaintChildren(ChromeCanvas* canvas) {
415 int i, c;
416 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
417 View* child = GetChildViewAt(i);
418 if (!child) {
419 NOTREACHED() << "Should not have a NULL child View for index in bounds";
420 continue;
421 }
422 child->ProcessPaint(canvas);
423 }
424}
425
426void View::ProcessPaint(ChromeCanvas* canvas) {
427 if (!IsVisible()) {
428 return;
429 }
430
431 // We're going to modify the canvas, save it's state first.
432 canvas->save();
433
434 // Paint this View and its children, setting the clip rect to the bounds
435 // of this View and translating the origin to the local bounds' top left
436 // point.
437 //
438 // Note that the X (or left) position we pass to ClipRectInt takes into
439 // consideration whether or not the view uses a right-to-left layout so that
440 // we paint our view in its mirrored position if need be.
441 if (canvas->ClipRectInt(MirroredX(), bounds_.top, bounds_.Width(),
442 bounds_.Height())) {
443 // Non-empty clip, translate the graphics such that 0,0 corresponds to
444 // where this view is located (related to its parent).
445 canvas->TranslateInt(MirroredX(), bounds_.top);
446
447 // Save the state again, so that any changes don't effect PaintChildren.
448 canvas->save();
449
450 // If the View we are about to paint requested the canvas to be flipped, we
451 // should change the transform appropriately.
452 bool flip_canvas = FlipCanvasOnPaintForRTLUI();
453 if (flip_canvas) {
454 canvas->TranslateInt(GetWidth(), 0);
455 canvas->ScaleInt(-1, 1);
456 canvas->save();
457 }
458
459 Paint(canvas);
460
461 // We must undo the canvas mirroring once the View is done painting so that
462 // we don't pass the canvas with the mirrored transform to Views that
463 // didn't request the canvas to be flipped.
464 if (flip_canvas) {
465 canvas->restore();
466 }
467 canvas->restore();
468 PaintChildren(canvas);
469 }
470
471 // Restore the canvas's original transform.
472 canvas->restore();
473}
474
475void View::PaintNow() {
476 if (!IsVisible()) {
477 return;
478 }
479
480 View* view = GetParent();
481 if (view)
482 view->PaintNow();
483}
484
485void View::PaintFloatingView(ChromeCanvas* canvas, View* view,
486 int x, int y, int w, int h) {
487 if (should_restore_focus_ && ShouldRestoreFloatingViewFocus()) {
488 // We are painting again a floating view, this is a good time to restore the
489 // focus to the last focused floating view if any.
490 should_restore_focus_ = false;
491 restore_focus_view_task_ = new RestoreFocusTask(this);
492 MessageLoop::current()->PostTask(FROM_HERE, restore_focus_view_task_);
493 }
494 View* saved_parent = view->GetParent();
495 view->SetParent(this);
496 view->SetBounds(x, y, w, h);
497 view->Layout();
498 view->ProcessPaint(canvas);
499 view->SetParent(saved_parent);
500}
501
502void View::SetBackground(Background* b) {
503 if (background_ != b)
504 delete background_;
505 background_ = b;
506}
507
508const Background* View::GetBackground() const {
509 return background_;
510}
511
512void View::SetBorder(Border* b) {
513 if (border_ != b)
514 delete border_;
515 border_ = b;
516}
517
518const Border* View::GetBorder() const {
519 return border_;
520}
521
522gfx::Insets View::GetInsets() const {
523 const Border* border = GetBorder();
524 gfx::Insets insets;
525 if (border)
526 border->GetInsets(&insets);
527 return insets;
528}
529
530void View::SetContextMenuController(ContextMenuController* menu_controller) {
531 context_menu_controller_ = menu_controller;
532}
533
534/////////////////////////////////////////////////////////////////////////////
535//
536// View - tree
537//
538/////////////////////////////////////////////////////////////////////////////
539
540bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
541 const bool enabled = enabled_;
542 int drag_operations;
543 if (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.GetLocation()))
544 drag_operations = GetDragOperations(e.GetX(), e.GetY());
545 else
546 drag_operations = 0;
547 ContextMenuController* context_menu_controller = context_menu_controller_;
548
549 const bool result = OnMousePressed(e);
550 // WARNING: we may have been deleted, don't use any View variables;
551
552 if (!enabled)
553 return result;
554
555 if (drag_operations != DragDropTypes::DRAG_NONE) {
556 drag_info->PossibleDrag(e.GetX(), e.GetY());
557 return true;
558 }
559 return !!context_menu_controller || result;
560}
561
562bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
563 // Copy the field, that way if we're deleted after drag and drop no harm is
564 // done.
565 ContextMenuController* context_menu_controller = context_menu_controller_;
566 const bool possible_drag = drag_info->possible_drag;
567 if (possible_drag && ExceededDragThreshold(drag_info->start_x - e.GetX(),
568 drag_info->start_y - e.GetY())) {
569 DoDrag(e, drag_info->start_x, drag_info->start_y);
570 } else {
571 if (OnMouseDragged(e))
572 return true;
573 // Fall through to return value based on context menu controller.
574 }
575 // WARNING: we may have been deleted.
576 return (context_menu_controller != NULL) || possible_drag;
577}
578
579void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
580 if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
581 // Assume that if there is a context menu controller we won't be deleted
582 // from mouse released.
583 CPoint location(e.GetX(), e.GetY());
584 ConvertPointToScreen(this, &location);
585 ContextMenuController* context_menu_controller = context_menu_controller_;
586 OnMouseReleased(e, canceled);
587 context_menu_controller_->ShowContextMenu(this, location.x, location.y,
588 true);
589 } else {
590 OnMouseReleased(e, canceled);
591 }
592 // WARNING: we may have been deleted.
593}
594
595void View::DoDrag(const MouseEvent& e, int press_x, int press_y) {
596 scoped_refptr<OSExchangeData> data = new OSExchangeData;
597 WriteDragData(press_x, press_y, data.get());
598
599 // Message the RootView to do the drag and drop. That way if we're removed
600 // the RootView can detect it and avoid callins us back.
601 RootView* root_view = GetRootView();
602 root_view->StartDragForViewFromMouseEvent(
603 this, data, GetDragOperations(press_x, press_y));
604}
605
606void View::AddChildView(View* v) {
607 AddChildView(static_cast<int>(child_views_.size()), v, false);
608}
609
610void View::AddChildView(int index, View* v) {
611 AddChildView(index, v, false);
612}
613
614void View::AddChildView(int index, View* v, bool floating_view) {
615 // Remove the view from its current parent if any.
616 if (v->GetParent())
617 v->GetParent()->RemoveChildView(v);
618
619 if (!floating_view) {
620 // Sets the prev/next focus views.
621 InitFocusSiblings(v, index);
622 }
623
624 // Let's insert the view.
625 child_views_.insert(child_views_.begin() + index, v);
626 v->SetParent(this);
627
628 for (View* p = this; p; p = p->GetParent()) {
629 p->ViewHierarchyChangedImpl(false, true, this, v);
630 }
631 v->PropagateAddNotifications(this, v);
632 UpdateTooltip();
633 RootView* root = GetRootView();
634 if (root)
635 RegisterChildrenForVisibleBoundsNotification(root, v);
636
637 if (layout_manager_.get())
638 layout_manager_->ViewAdded(this, v);
639}
640
641View* View::GetChildViewAt(int index) const {
642 return index < GetChildViewCount() ? child_views_[index] : NULL;
643}
644
645int View::GetChildViewCount() const {
646 return static_cast<int>(child_views_.size());
647}
648
649void View::RemoveChildView(View* a_view) {
650 DoRemoveChildView(a_view, true, true, false);
651}
652
653void View::RemoveAllChildViews(bool delete_views) {
654 ViewList::iterator iter;
655 while ((iter = child_views_.begin()) != child_views_.end()) {
656 DoRemoveChildView(*iter, false, false, delete_views);
657 }
658 UpdateTooltip();
659}
660
661void View::DoRemoveChildView(View* a_view,
662 bool update_focus_cycle,
663 bool update_tool_tip,
664 bool delete_removed_view) {
665#ifndef NDEBUG
666 DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
667 "during a paint, this will seriously " <<
668 "mess things up!";
669#endif
670 DCHECK(a_view);
671 const ViewList::iterator i = find(child_views_.begin(),
672 child_views_.end(),
673 a_view);
674 if (i != child_views_.end()) {
675 if (update_focus_cycle && !a_view->IsFloatingView()) {
676 // Let's remove the view from the focus traversal.
677 View* next_focusable = a_view->next_focusable_view_;
678 View* prev_focusable = a_view->previous_focusable_view_;
679 if (prev_focusable)
680 prev_focusable->next_focusable_view_ = next_focusable;
681 if (next_focusable)
682 next_focusable->previous_focusable_view_ = prev_focusable;
683 }
684
685 RootView* root = GetRootView();
686 if (root)
687 UnregisterChildrenForVisibleBoundsNotification(root, a_view);
688 a_view->PropagateRemoveNotifications(this);
689 a_view->SetParent(NULL);
690
691 if (delete_removed_view && a_view->IsParentOwned())
692 delete a_view;
693
694 child_views_.erase(i);
695 }
696
697 if (update_tool_tip)
698 UpdateTooltip();
699
700 if (layout_manager_.get())
701 layout_manager_->ViewRemoved(this, a_view);
702}
703
704void View::PropagateRemoveNotifications(View* parent) {
705 int i, c;
706 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
707 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
708 }
709
710 View *t;
711 for (t = this; t; t = t->GetParent()) {
712 t->ViewHierarchyChangedImpl(true, false, parent, this);
713 }
714}
715
716void View::PropagateAddNotifications(View* parent, View* child) {
717 int i, c;
718 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
719 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
720 }
721 ViewHierarchyChangedImpl(true, true, parent, child);
722}
723
724#ifndef NDEBUG
725bool View::IsProcessingPaint() const {
726 return GetParent() && GetParent()->IsProcessingPaint();
727}
728#endif
729
730void View::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
731}
732
733void View::ViewHierarchyChangedImpl(bool register_accelerators,
734 bool is_add, View *parent, View *child) {
735 if (register_accelerators) {
736 if (is_add) {
737 // If you get this registration, you are part of a subtree that has been
738 // added to the view hierarchy.
739 RegisterAccelerators();
740 } else {
741 if (child == this)
742 UnregisterAccelerators();
743 }
744 }
745
746 ViewHierarchyChanged(is_add, parent, child);
747}
748
749void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
750 int i, c;
751 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
752 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
753 }
754 VisibilityChanged(start, is_visible);
755}
756
757void View::VisibilityChanged(View* starting_from, bool is_visible) {
758}
759
760View* View::GetViewForPoint(const CPoint& point) {
761 return GetViewForPoint(point, true);
762}
763
764void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
765 if (notify_when_visible_bounds_in_root_changes_ == value)
766 return;
767 notify_when_visible_bounds_in_root_changes_ = value;
768 RootView* root = GetRootView();
769 if (root) {
770 if (value)
771 root->RegisterViewForVisibleBoundsNotification(this);
772 else
773 root->UnregisterViewForVisibleBoundsNotification(this);
774 }
775}
776
777bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
778 return notify_when_visible_bounds_in_root_changes_;
779}
780
781View* View::GetViewForPoint(const CPoint& point, bool can_create_floating) {
782 // Walk the child Views recursively looking for the View that most
783 // tightly encloses the specified point.
784 for (int i = GetChildViewCount() - 1 ; i >= 0 ; --i) {
785 View* child = GetChildViewAt(i);
786 if (!child->IsVisible()) {
787 continue;
788 }
789 CRect bounds;
790 child->GetBounds(&bounds, APPLY_MIRRORING_TRANSFORMATION);
791 if (bounds.PtInRect(point)) {
792 CPoint cl(point);
793 cl.Offset(-bounds.left, -bounds.top);
794 return child->GetViewForPoint(cl, true);
795 }
796 }
797
798 // We haven't found a view for the point. Try to create floating views
799 // and try again if one was created.
800 // can_create_floating makes sure we don't try forever even if
801 // GetFloatingViewIDForPoint lies or if RetrieveFloatingViewForID creates a
802 // view which doesn't contain the provided point
803 int id;
804 if (can_create_floating && GetFloatingViewIDForPoint(point.x, point.y, &id)) {
805 RetrieveFloatingViewForID(id); // This creates the floating view.
806 return GetViewForPoint(point, false);
807 }
808 return this;
809}
810
811ViewContainer* View::GetViewContainer() const {
812 // The root view holds a reference to this view hierarchy's container.
813 return parent_ ? parent_->GetViewContainer() : NULL;
814}
815
816// Get the containing RootView
817RootView* View::GetRootView() {
818 ViewContainer* vc = GetViewContainer();
819 if (vc) {
820 return vc->GetRootView();
821 } else {
822 return NULL;
823 }
824}
825
826View* View::GetViewByID(int id) const {
827 if (id == id_)
828 return const_cast<View*>(this);
829
830 int view_count = GetChildViewCount();
831 for (int i = 0; i < view_count; ++i) {
832 View* child = GetChildViewAt(i);
833 View* view = child->GetViewByID(id);
834 if (view)
835 return view;
836 }
837 return NULL;
838}
839
840void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
841 if (group_ == group_id)
842 out->push_back(this);
843
844 int view_count = GetChildViewCount();
845 for (int i = 0; i < view_count; ++i)
846 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
847}
848
849View* View::GetSelectedViewForGroup(int group_id) {
850 std::vector<View*> views;
851 GetRootView()->GetViewsWithGroup(group_id, &views);
852 if (views.size() > 0)
853 return views[0];
854 else
855 return NULL;
856}
857
858void View::SetID(int id) {
859 id_ = id;
860}
861
862int View::GetID() const {
863 return id_;
864}
865
866void View::SetGroup(int gid) {
867 group_ = gid;
868}
869
870int View::GetGroup() const {
871 return group_;
872}
873
874void View::SetParent(View* parent) {
875 if (parent != parent_) {
876 parent_ = parent;
877 }
878}
879
880bool View::IsParentOf(View* v) const {
881 DCHECK(v);
882 View* parent = v->GetParent();
883 while (parent) {
884 if (this == parent)
885 return true;
886 parent = parent->GetParent();
887 }
888 return false;
889}
890
891int View::GetChildIndex(View* v) const {
892 for (int i = 0; i < GetChildViewCount(); i++) {
893 if (v == GetChildViewAt(i))
894 return i;
895 }
896 return -1;
897}
898
899///////////////////////////////////////////////////////////////////////////////
900//
901// View - focus
902//
903///////////////////////////////////////////////////////////////////////////////
904
905View* View::GetNextFocusableView() {
906 return next_focusable_view_;
907}
908
909View* View::GetPreviousFocusableView() {
910 return previous_focusable_view_;
911}
912
913void View::SetNextFocusableView(View* view) {
914 view->previous_focusable_view_ = this;
915 next_focusable_view_ = view;
916}
917
918void View::InitFocusSiblings(View* v, int index) {
919 int child_count = static_cast<int>(child_views_.size());
920
921 if (child_count == 0) {
922 v->next_focusable_view_ = NULL;
923 v->previous_focusable_view_ = NULL;
924 } else {
925 if (index == child_count) {
926 // We are inserting at the end, but the end of the child list may not be
927 // the last focusable element. Let's try to find an element with no next
928 // focusable element to link to.
929 View* last_focusable_view = NULL;
930 for (std::vector<View*>::iterator iter = child_views_.begin();
931 iter != child_views_.end(); ++iter) {
932 if (!(*iter)->next_focusable_view_) {
933 last_focusable_view = *iter;
934 break;
935 }
936 }
937 if (last_focusable_view == NULL) {
938 // Hum... there is a cycle in the focus list. Let's just insert ourself
939 // after the last child.
940 View* prev = child_views_[index - 1];
941 v->previous_focusable_view_ = prev;
942 v->next_focusable_view_ = prev->next_focusable_view_;
943 prev->next_focusable_view_->previous_focusable_view_ = v;
944 prev->next_focusable_view_ = v;
945 } else {
946 last_focusable_view->next_focusable_view_ = v;
947 v->next_focusable_view_ = NULL;
948 v->previous_focusable_view_ = last_focusable_view;
949 }
950 } else {
951 View* prev = child_views_[index]->GetPreviousFocusableView();
952 v->previous_focusable_view_ = prev;
953 v->next_focusable_view_ = child_views_[index];
954 if (prev)
955 prev->next_focusable_view_ = v;
956 child_views_[index]->previous_focusable_view_ = v;
957 }
958 }
959}
960
961#ifndef NDEBUG
962void View::PrintViewHierarchy() {
963 PrintViewHierarchyImp(0);
964}
965
966void View::PrintViewHierarchyImp(int indent) {
967 std::wostringstream buf;
968 int ind = indent;
969 while (ind-- > 0)
970 buf << L' ';
971 buf << UTF8ToWide(GetClassName());
972 buf << L' ';
973 buf << GetID();
974 buf << L' ';
975 buf << bounds_.left << L"," << bounds_.top << L",";
976 buf << bounds_.right << L"," << bounds_.bottom;
977 buf << L' ';
978 buf << this;
979
980 LOG(INFO) << buf.str();
981 std::cout << buf.str() << std::endl;
982
983 for (int i = 0; i < GetChildViewCount(); ++i) {
984 GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
985 }
986}
987
988
989void View::PrintFocusHierarchy() {
990 PrintFocusHierarchyImp(0);
991}
992
993void View::PrintFocusHierarchyImp(int indent) {
994 std::wostringstream buf;
995 int ind = indent;
996 while (ind-- > 0)
997 buf << L' ';
998 buf << UTF8ToWide(GetClassName());
999 buf << L' ';
1000 buf << GetID();
1001 buf << L' ';
1002 buf << GetClassName().c_str();
1003 buf << L' ';
1004 buf << this;
1005
1006 LOG(INFO) << buf.str();
1007 std::cout << buf.str() << std::endl;
1008
1009 if (GetChildViewCount() > 0)
1010 GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
1011
1012 View* v = GetNextFocusableView();
1013 if (v)
1014 v->PrintFocusHierarchyImp(indent);
1015}
1016#endif
1017
1018////////////////////////////////////////////////////////////////////////////////
1019//
1020// View - accelerators
1021//
1022////////////////////////////////////////////////////////////////////////////////
1023
1024void View::AddAccelerator(const Accelerator& accelerator) {
1025 if (!accelerators_.get())
1026 accelerators_.reset(new std::vector<Accelerator>());
1027 accelerators_->push_back(accelerator);
1028 RegisterAccelerators();
1029}
1030
1031void View::ResetAccelerators() {
1032 if (accelerators_.get()) {
1033 UnregisterAccelerators();
1034 accelerators_->clear();
1035 accelerators_.reset();
1036 }
1037}
1038
1039void View::RegisterAccelerators() {
1040 if (!accelerators_.get())
1041 return;
1042
1043 RootView* root_view = GetRootView();
1044 if (!root_view) {
1045 // We are not yet part of a view hierarchy, we'll register ourselves once
1046 // added to one.
1047 return;
1048 }
1049 FocusManager* focus_manager = GetFocusManager();
1050 if (!focus_manager) {
1051 // Some crash reports seem to show that we may get cases where we have no
1052 // focus manager (see bug #1291225). This should never be the case, just
1053 // making sure we don't crash.
1054 NOTREACHED();
1055 return;
1056 }
1057 for (std::vector<Accelerator>::const_iterator iter = accelerators_->begin();
1058 iter != accelerators_->end(); ++iter) {
1059 focus_manager->RegisterAccelerator(*iter, this);
1060 }
1061}
1062
1063void View::UnregisterAccelerators() {
1064 if (!accelerators_.get())
1065 return;
1066
1067 RootView* root_view = GetRootView();
1068 if (root_view) {
1069 FocusManager* focus_manager = GetFocusManager();
1070 if (focus_manager) {
1071 // We may not have a FocusManager if the window containing us is being
1072 // closed, in which case the FocusManager is being deleted so there is
1073 // nothing to unregister.
1074 focus_manager->UnregisterAccelerators(this);
1075 }
1076 }
1077}
1078
1079/////////////////////////////////////////////////////////////////////////////
1080//
1081// View - accessibility
1082//
1083/////////////////////////////////////////////////////////////////////////////
1084
1085AccessibleWrapper* View::GetAccessibleWrapper() {
1086 if (accessibility_.get() == NULL) {
1087 accessibility_.reset(new AccessibleWrapper(this));
1088 }
1089 return accessibility_.get();
1090}
1091
1092/////////////////////////////////////////////////////////////////////////////
1093//
1094// View - floating views
1095//
1096/////////////////////////////////////////////////////////////////////////////
1097
1098bool View::IsFloatingView() {
1099 if (!parent_)
1100 return false;
1101
1102 return parent_->floating_views_ids_.find(this) !=
1103 parent_->floating_views_ids_.end();
1104}
1105
1106// default implementation does nothing
1107bool View::GetFloatingViewIDForPoint(int x, int y, int* id) {
1108 return false;
1109}
1110
1111int View::GetFloatingViewCount() const {
1112 return static_cast<int>(floating_views_.size());
1113}
1114
1115View* View::RetrieveFloatingViewParent() {
1116 View* v = this;
1117 while (v) {
1118 if (v->IsFloatingView())
1119 return v;
1120 v = v->GetParent();
1121 }
1122 return NULL;
1123}
1124
1125bool View::EnumerateFloatingViews(FloatingViewPosition position,
1126 int starting_id, int* id) {
1127 return false;
1128}
1129
1130int View::GetDragOperations(int press_x, int press_y) {
1131 if (!drag_controller_)
1132 return DragDropTypes::DRAG_NONE;
1133 return drag_controller_->GetDragOperations(this, press_x, press_y);
1134}
1135
1136void View::WriteDragData(int press_x, int press_y, OSExchangeData* data) {
1137 DCHECK(drag_controller_);
1138 drag_controller_->WriteDragData(this, press_x, press_y, data);
1139}
1140
1141void View::OnDragDone() {
1142}
1143
1144bool View::InDrag() {
1145 RootView* root_view = GetRootView();
1146 return root_view ? (root_view->GetDragView() == this) : false;
1147}
1148
1149View* View::ValidateFloatingViewForID(int id) {
1150 return NULL;
1151}
1152
1153bool View::ShouldRestoreFloatingViewFocus() {
1154 return true;
1155}
1156
1157void View::AttachFloatingView(View* v, int id) {
1158 floating_views_.push_back(v);
1159 floating_views_ids_[v] = id;
1160 AddChildView(static_cast<int>(child_views_.size()), v, true);
1161}
1162
1163bool View::HasFloatingViewForPoint(int x, int y) {
1164 int i, c;
1165 View* v;
1166 gfx::Rect r;
1167
1168 for (i = 0, c = static_cast<int>(floating_views_.size()); i < c; ++i) {
1169 v = floating_views_[i];
1170 r.SetRect(v->GetX(APPLY_MIRRORING_TRANSFORMATION), v->GetY(),
1171 v->GetWidth(), v->GetHeight());
1172 if (r.Contains(x, y))
1173 return true;
1174 }
1175 return false;
1176}
1177
1178void View::DetachAllFloatingViews() {
1179 RootView* root_view = GetRootView();
1180 View* focused_view = NULL;
1181 FocusManager* focus_manager = NULL;
1182 if (root_view) {
1183 // We may be called when we are not attached to a root view in which case
1184 // there is nothing to do for focus.
1185 focus_manager = GetFocusManager();
1186 if (focus_manager) {
1187 // We may not have a focus manager (if we are detached from a top window).
1188 focused_view = focus_manager->GetFocusedView();
1189 }
1190 }
1191
1192 int c = static_cast<int>(floating_views_.size());
1193 while (--c >= 0) {
1194 // If the focused view is a floating view or a floating view's children,
1195 // use the focus manager to store it.
1196 int tmp_id;
1197 if (focused_view &&
1198 ((focused_view == floating_views_[c]) ||
1199 floating_views_[c]->IsParentOf(focused_view))) {
1200 // We call EnumerateFloatingView to make sure the floating view is still
1201 // valid: the model may have changed and could not know anything about
1202 // that floating view anymore.
1203 if (EnumerateFloatingViews(CURRENT,
1204 floating_views_[c]->GetFloatingViewID(),
1205 &tmp_id)) {
1206 focus_manager->StoreFocusedView();
1207 should_restore_focus_ = true;
1208 }
1209 focused_view = NULL;
1210 }
1211
1212 RemoveChildView(floating_views_[c]);
1213 delete floating_views_[c];
1214 }
1215 floating_views_.clear();
1216 floating_views_ids_.clear();
1217}
1218
1219int View::GetFloatingViewID() {
1220 DCHECK(IsFloatingView());
1221 std::map<View*, int>::iterator iter = parent_->floating_views_ids_.find(this);
1222 DCHECK(iter != parent_->floating_views_ids_.end());
1223 return iter->second;
1224}
1225
1226View* View::RetrieveFloatingViewForID(int id) {
1227 for (ViewList::const_iterator iter = floating_views_.begin();
1228 iter != floating_views_.end(); ++iter) {
1229 if ((*iter)->GetFloatingViewID() == id)
1230 return *iter;
1231 }
1232 return ValidateFloatingViewForID(id);
1233}
1234
1235void View::RestoreFloatingViewFocus() {
1236 // Clear the reference to the task as if we have been triggered by it, it will
1237 // soon be invalid.
1238 restore_focus_view_task_ = NULL;
1239 should_restore_focus_ = false;
1240
1241 GetFocusManager()->RestoreFocusedView();
1242}
1243
1244// static
1245bool View::EnumerateFloatingViewsForInterval(int low_bound, int high_bound,
1246 bool ascending_order,
1247 FloatingViewPosition position,
1248 int starting_id,
1249 int* id) {
1250 DCHECK(low_bound <= high_bound);
1251 if (low_bound >= high_bound)
1252 return false;
1253
1254 switch (position) {
1255 case CURRENT:
1256 if ((starting_id >= low_bound) && (starting_id < high_bound)) {
1257 *id = starting_id;
1258 return true;
1259 }
1260 return false;
1261 case FIRST:
1262 *id = ascending_order ? low_bound : high_bound - 1;
1263 return true;
1264 case LAST:
1265 *id = ascending_order ? high_bound - 1 : low_bound;
1266 return true;
1267 case NEXT:
1268 case PREVIOUS:
1269 if (((position == NEXT) && ascending_order) ||
1270 ((position == PREVIOUS) && !ascending_order)) {
1271 starting_id++;
1272 if (starting_id < high_bound) {
1273 *id = starting_id;
1274 return true;
1275 }
1276 return false;
1277 }
1278 DCHECK(((position == NEXT) && !ascending_order) ||
1279 ((position == PREVIOUS) && ascending_order));
1280 starting_id--;
1281 if (starting_id >= low_bound) {
1282 *id = starting_id;
1283 return true;
1284 }
1285 return false;
1286 default:
1287 NOTREACHED();
1288 }
1289 return false;
1290}
1291
1292// static
1293void View::ConvertPointToView(View* src,
1294 View* dst,
1295 gfx::Point* point) {
1296 ConvertPointToView(src, dst, point, true);
1297}
1298
1299// static
1300void View::ConvertPointToView(View* src,
1301 View* dst,
1302 CPoint* point) {
1303 gfx::Point tmp_point(point->x, point->y);
1304 ConvertPointToView(src, dst, &tmp_point, true);
1305 point->x = tmp_point.x();
1306 point->y = tmp_point.y();
1307}
1308
1309// static
1310void View::ConvertPointToView(View* src,
1311 View* dst,
1312 gfx::Point* point,
1313 bool try_other_direction) {
1314 // src can be NULL
1315 DCHECK(dst);
1316 DCHECK(point);
1317
1318 View* v;
1319 gfx::Point offset;
1320
1321 for (v = dst; v && v != src; v = v->GetParent()) {
1322 offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
1323 offset.y() + v->GetY());
1324 }
1325
1326 // The source was not found. The caller wants a conversion
1327 // from a view to a transitive parent.
1328 if (src && v == NULL && try_other_direction) {
1329 gfx::Point p;
1330 // note: try_other_direction is force to FALSE so we don't
1331 // end up in an infinite recursion should both src and dst
1332 // are not parented.
1333 ConvertPointToView(dst, src, &p, false);
1334 // since the src and dst are inverted, p should also be negated
1335 point->SetPoint(point->x() - p.x(), point->y() - p.y());
1336 } else {
1337 point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
1338
1339 // If src is NULL, sp is in the screen coordinate system
1340 if (src == NULL) {
1341 ViewContainer* vc = dst->GetViewContainer();
1342 if (vc) {
1343 CRect b;
1344 vc->GetBounds(&b, false);
1345 point->SetPoint(point->x() - b.left, point->y() - b.top);
1346 }
1347 }
1348 }
1349}
1350
1351// static
1352void View::ConvertPointToViewContainer(View* src, CPoint* p) {
1353 DCHECK(src);
1354 DCHECK(p);
1355 View *v;
1356 CPoint offset(0, 0);
1357
1358 for (v = src; v; v = v->GetParent()) {
1359 offset.x += v->GetX(APPLY_MIRRORING_TRANSFORMATION);
1360 offset.y += v->GetY();
1361 }
1362 p->x += offset.x;
1363 p->y += offset.y;
1364}
1365
1366// static
1367void View::ConvertPointFromViewContainer(View *source, CPoint *p) {
1368 CPoint t(0, 0);
1369 ConvertPointToViewContainer(source, &t);
1370 p->x -= t.x;
1371 p->y -= t.y;
1372}
1373
1374// static
1375void View::ConvertPointToScreen(View* src, CPoint* p) {
1376 DCHECK(src);
1377 DCHECK(p);
1378
1379 // If the view is not connected to a tree, do nothing
1380 if (src->GetViewContainer() == NULL) {
1381 return;
1382 }
1383
1384 ConvertPointToViewContainer(src, p);
1385 ViewContainer* vc = src->GetViewContainer();
1386 if (vc) {
1387 CRect r;
1388 vc->GetBounds(&r, false);
1389 p->x += r.left;
1390 p->y += r.top;
1391 }
1392}
1393
1394/////////////////////////////////////////////////////////////////////////////
1395//
1396// View - event handlers
1397//
1398/////////////////////////////////////////////////////////////////////////////
1399
1400bool View::OnMousePressed(const MouseEvent& e) {
1401 return false;
1402}
1403
1404bool View::OnMouseDragged(const MouseEvent& e) {
1405 return false;
1406}
1407
1408void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
1409}
1410
1411void View::OnMouseMoved(const MouseEvent& e) {
1412}
1413
1414void View::OnMouseEntered(const MouseEvent& e) {
1415}
1416
1417void View::OnMouseExited(const MouseEvent& e) {
1418}
1419
1420void View::SetMouseHandler(View *new_mouse_handler) {
1421 // It is valid for new_mouse_handler to be NULL
1422 if (parent_) {
1423 parent_->SetMouseHandler(new_mouse_handler);
1424 }
1425}
1426
1427void View::SetVisible(bool flag) {
1428 if (flag != is_visible_) {
1429 // If the tab is currently visible, schedule paint to
1430 // refresh parent
1431 if (IsVisible()) {
1432 SchedulePaint();
1433 }
1434
1435 is_visible_ = flag;
1436
1437 // This notifies all subviews recursively.
1438 PropagateVisibilityNotifications(this, flag);
1439
1440 // If we are newly visible, schedule paint.
1441 if (IsVisible()) {
1442 SchedulePaint();
1443 }
1444 }
1445}
1446
1447bool View::IsVisibleInRootView() const {
1448 View* parent = GetParent();
1449 if (IsVisible() && parent)
1450 return parent->IsVisibleInRootView();
1451 else
1452 return false;
1453}
1454
1455bool View::HitTest(const CPoint &l) const {
1456 if (l.x >= 0 && l.x < static_cast<int>(GetWidth()) &&
1457 l.y >= 0 && l.y < static_cast<int>(GetHeight())) {
1458 return true;
1459 } else {
1460 return false;
1461 }
1462}
1463
1464HCURSOR View::GetCursorForPoint(Event::EventType event_type, int x, int y) {
1465 return NULL;
1466}
1467
1468/////////////////////////////////////////////////////////////////////////////
1469//
1470// View - keyboard and focus
1471//
1472/////////////////////////////////////////////////////////////////////////////
1473
1474void View::RequestFocus() {
1475 RootView* rv = GetRootView();
1476 if (rv) {
1477 rv->FocusView(this);
1478 }
1479}
1480
1481void View::WillGainFocus() {
1482}
1483
1484void View::DidGainFocus() {
1485}
1486
1487void View::WillLoseFocus() {
1488}
1489
1490bool View::OnKeyPressed(const KeyEvent& e) {
1491 return false;
1492}
1493
1494bool View::OnKeyReleased(const KeyEvent& e) {
1495 return false;
1496}
1497
1498bool View::OnMouseWheel(const MouseWheelEvent& e) {
1499 return false;
1500}
1501
1502void View::SetDragController(DragController* drag_controller) {
1503 drag_controller_ = drag_controller;
1504}
1505
1506DragController* View::GetDragController() {
1507 return drag_controller_;
1508}
1509
1510bool View::CanDrop(const OSExchangeData& data) {
1511 return false;
1512}
1513
1514void View::OnDragEntered(const DropTargetEvent& event) {
1515}
1516
1517int View::OnDragUpdated(const DropTargetEvent& event) {
1518 return DragDropTypes::DRAG_NONE;
1519}
1520
1521void View::OnDragExited() {
1522}
1523
1524int View::OnPerformDrop(const DropTargetEvent& event) {
1525 return DragDropTypes::DRAG_NONE;
1526}
1527
1528static int GetHorizontalDragThreshold() {
1529 static int threshold = -1;
1530 if (threshold == -1)
1531 threshold = GetSystemMetrics(SM_CXDRAG) / 2;
1532 return threshold;
1533}
1534
1535static int GetVerticalDragThreshold() {
1536 static int threshold = -1;
1537 if (threshold == -1)
1538 threshold = GetSystemMetrics(SM_CYDRAG) / 2;
1539 return threshold;
1540}
1541
1542// static
1543bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1544 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1545 abs(delta_y) > GetVerticalDragThreshold());
1546}
1547
1548void View::Focus() {
1549 // Set the native focus to the root view window so it receives the keyboard
1550 // messages.
1551 FocusManager* focus_manager = GetFocusManager();
1552 if (focus_manager)
1553 focus_manager->FocusHWND(GetRootView()->GetViewContainer()->GetHWND());
1554}
1555
1556bool View::CanProcessTabKeyEvents() {
1557 return false;
1558}
1559
1560// Tooltips -----------------------------------------------------------------
1561bool View::GetTooltipText(int x, int y, std::wstring* tooltip) {
1562 return false;
1563}
1564
1565bool View::GetTooltipTextOrigin(int x, int y, CPoint* loc) {
1566 return false;
1567}
1568
1569void View::TooltipTextChanged() {
1570 ViewContainer* view_container = GetViewContainer();
1571 if (view_container != NULL && view_container->GetTooltipManager())
1572 view_container->GetTooltipManager()->TooltipTextChanged(this);
1573}
1574
1575void View::UpdateTooltip() {
1576 ViewContainer* view_container = GetViewContainer();
1577 if (view_container != NULL && view_container->GetTooltipManager())
1578 view_container->GetTooltipManager()->UpdateTooltip();
1579}
1580
1581void View::SetParentOwned(bool f) {
1582 is_parent_owned_ = f;
1583}
1584
1585bool View::IsParentOwned() const {
1586 return is_parent_owned_;
1587}
1588
1589std::string View::GetClassName() const {
1590 return kViewClassName;
1591}
1592
1593gfx::Rect View::GetVisibleBounds() {
1594 gfx::Rect vis_bounds(0, 0, GetWidth(), GetHeight());
1595 gfx::Rect ancestor_bounds;
1596 View* view = this;
1597 int root_x = 0;
1598 int root_y = 0;
1599 bool has_view_container = false;
1600 while (view != NULL && !vis_bounds.IsEmpty()) {
1601 root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
1602 root_y += view->GetY();
1603 vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->GetY());
1604 View* ancestor = view->GetParent();
1605 if (ancestor != NULL) {
1606 ancestor_bounds.SetRect(0, 0, ancestor->GetWidth(),
1607 ancestor->GetHeight());
1608 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
1609 } else if (!view->GetViewContainer()) {
1610 // If the view has no ViewContainer, we're not visible. Return an empty
1611 // rect.
1612 return gfx::Rect();
1613 }
1614 view = ancestor;
1615 }
1616 if (vis_bounds.IsEmpty())
1617 return vis_bounds;
1618 // Convert back to this views coordinate system.
1619 vis_bounds.Offset(-root_x, -root_y);
1620 return vis_bounds;
1621}
1622
1623int View::GetPageScrollIncrement(ScrollView* scroll_view,
1624 bool is_horizontal, bool is_positive) {
1625 return 0;
1626}
1627
1628int View::GetLineScrollIncrement(ScrollView* scroll_view,
1629 bool is_horizontal, bool is_positive) {
1630 return 0;
1631}
1632
1633// static
1634void View::RegisterChildrenForVisibleBoundsNotification(
1635 RootView* root, View* view) {
1636 DCHECK(root && view);
1637 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1638 root->RegisterViewForVisibleBoundsNotification(view);
1639 for (int i = 0; i < view->GetChildViewCount(); ++i)
1640 RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i));
1641}
1642
1643// static
1644void View::UnregisterChildrenForVisibleBoundsNotification(
1645 RootView* root, View* view) {
1646 DCHECK(root && view);
1647 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1648 root->UnregisterViewForVisibleBoundsNotification(view);
1649 for (int i = 0; i < view->GetChildViewCount(); ++i)
1650 UnregisterChildrenForVisibleBoundsNotification(root,
1651 view->GetChildViewAt(i));
1652}
1653
1654void View::AddDescendantToNotify(View* view) {
1655 DCHECK(view);
1656 if (!descendants_to_notify_.get())
1657 descendants_to_notify_.reset(new ViewList());
1658 descendants_to_notify_->push_back(view);
1659}
1660
1661void View::RemoveDescendantToNotify(View* view) {
1662 DCHECK(view && descendants_to_notify_.get());
1663 ViewList::iterator i = find(descendants_to_notify_->begin(),
1664 descendants_to_notify_->end(),
1665 view);
1666 DCHECK(i != descendants_to_notify_->end());
1667 descendants_to_notify_->erase(i);
1668 if (descendants_to_notify_->empty())
1669 descendants_to_notify_.reset();
1670}
1671
1672// static
1673bool View::GetViewPath(View* start, View* end, std::vector<int>* path) {
1674 while (end && (end != start)) {
1675 View* parent = end->GetParent();
1676 if (!parent)
1677 return false;
1678 path->insert(path->begin(), parent->GetChildIndex(end));
1679 end = parent;
1680 }
1681 return end == start;
1682}
1683
1684// static
1685View* View::GetViewForPath(View* start, const std::vector<int>& path) {
1686 View* v = start;
1687 for (std::vector<int>::const_iterator iter = path.begin();
1688 iter != path.end(); ++iter) {
1689 int index = *iter;
1690 if (index >= v->GetChildViewCount())
1691 return NULL;
1692 v = v->GetChildViewAt(index);
1693 }
1694 return v;
1695}
1696
1697// DropInfo --------------------------------------------------------------------
1698
1699void View::DragInfo::Reset() {
1700 possible_drag = false;
1701 start_x = start_y = 0;
1702}
1703
1704void View::DragInfo::PossibleDrag(int x, int y) {
1705 possible_drag = true;
1706 start_x = x;
1707 start_y = y;
1708}
1709
1710} // namespace