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