blob: 1dbe9f8c0e91efd63b2b714562a5c5079e09ffd3 [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"
[email protected]4d0bd102008-10-16 00:26:3025#include "chrome/views/container.h"
initial.commit09911bf2008-07-26 23:55:2926#include "chrome/views/layout_manager.h"
27#include "chrome/views/root_view.h"
28#include "chrome/views/tooltip_manager.h"
initial.commit09911bf2008-07-26 23:55:2929#include "SkShader.h"
30
[email protected]c2dacc92008-10-16 23:51:3831namespace views {
initial.commit09911bf2008-07-26 23:55:2932
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 {
[email protected]80f8b9f2008-10-16 18:17:47132 return settings == IGNORE_MIRRORING_TRANSFORMATION ? x() : MirroredX();
initial.commit09911bf2008-07-26 23:55:29133}
134
[email protected]80f8b9f2008-10-16 18:17:47135void View::SetBounds(const gfx::Rect& bounds) {
136 if (bounds == bounds_)
initial.commit09911bf2008-07-26 23:55:29137 return;
initial.commit09911bf2008-07-26 23:55:29138
[email protected]80f8b9f2008-10-16 18:17:47139 gfx::Rect prev = bounds_;
initial.commit09911bf2008-07-26 23:55:29140 bounds_ = bounds;
initial.commit09911bf2008-07-26 23:55:29141 DidChangeBounds(prev, bounds_);
142
143 RootView* root = GetRootView();
144 if (root) {
[email protected]80f8b9f2008-10-16 18:17:47145 bool size_changed = prev.size() != bounds_.size();
146 bool position_changed = prev.origin() != bounds_.origin();
initial.commit09911bf2008-07-26 23:55:29147 if (size_changed || position_changed)
148 root->ViewBoundsChanged(this, size_changed, position_changed);
149 }
150}
151
[email protected]80f8b9f2008-10-16 18:17:47152gfx::Rect View::GetLocalBounds(bool include_border) const {
153 if (include_border || border_ == NULL)
154 return gfx::Rect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29155
[email protected]80f8b9f2008-10-16 18:17:47156 gfx::Insets insets;
157 border_->GetInsets(&insets);
158 return gfx::Rect(insets.left(), insets.top(),
159 width() - insets.width(), height() - insets.height());
initial.commit09911bf2008-07-26 23:55:29160}
161
[email protected]0a1d36b22008-10-17 19:33:09162gfx::Point View::GetPosition() const {
163 return gfx::Point(GetX(APPLY_MIRRORING_TRANSFORMATION), y());
initial.commit09911bf2008-07-26 23:55:29164}
165
[email protected]154f8bc2008-10-15 18:02:30166gfx::Size View::GetPreferredSize() {
167 if (layout_manager_.get())
168 return layout_manager_->GetPreferredSize(this);
169 return gfx::Size();
initial.commit09911bf2008-07-26 23:55:29170}
171
172void View::SizeToPreferredSize() {
[email protected]154f8bc2008-10-15 18:02:30173 gfx::Size prefsize = GetPreferredSize();
174 if ((prefsize.width() != width()) || (prefsize.height() != height()))
175 SetBounds(x(), y(), prefsize.width(), prefsize.height());
initial.commit09911bf2008-07-26 23:55:29176}
177
[email protected]154f8bc2008-10-15 18:02:30178gfx::Size View::GetMinimumSize() {
179 return GetPreferredSize();
initial.commit09911bf2008-07-26 23:55:29180}
181
182int View::GetHeightForWidth(int w) {
183 if (layout_manager_.get())
184 return layout_manager_->GetPreferredHeightForWidth(this, w);
185
[email protected]154f8bc2008-10-15 18:02:30186 return GetPreferredSize().height();
initial.commit09911bf2008-07-26 23:55:29187}
188
[email protected]80f8b9f2008-10-16 18:17:47189void View::DidChangeBounds(const gfx::Rect& previous,
190 const gfx::Rect& current) {
191 Layout();
initial.commit09911bf2008-07-26 23:55:29192}
193
194void View::ScrollRectToVisible(int x, int y, int width, int height) {
195 View* parent = GetParent();
196
197 // We must take RTL UI mirroring into account when adjusting the position of
198 // the region.
199 if (parent)
200 parent->ScrollRectToVisible(
[email protected]6f3bb6c2008-09-17 22:25:33201 GetX(APPLY_MIRRORING_TRANSFORMATION) + x, View::y() + y, width, height);
initial.commit09911bf2008-07-26 23:55:29202}
203
204/////////////////////////////////////////////////////////////////////////////
205//
206// View - layout
207//
208/////////////////////////////////////////////////////////////////////////////
209
210void View::Layout() {
211 // Layout child Views
212 if (layout_manager_.get()) {
213 layout_manager_->Layout(this);
214 SchedulePaint();
215 }
216
217 // Lay out contents of child Views
218 int child_count = GetChildViewCount();
219 for (int i = 0; i < child_count; ++i) {
220 View* child = GetChildViewAt(i);
221 child->Layout();
222 }
223}
224
225LayoutManager* View::GetLayoutManager() const {
226 return layout_manager_.get();
227}
228
229void View::SetLayoutManager(LayoutManager* layout_manager) {
230 if (layout_manager_.get()) {
231 layout_manager_->Uninstalled(this);
232 }
233 layout_manager_.reset(layout_manager);
234 if (layout_manager_.get()) {
235 layout_manager_->Installed(this);
236 }
237}
238
[email protected]1eb89e82008-08-15 12:27:03239bool View::UILayoutIsRightToLeft() const {
240 return (ui_mirroring_is_enabled_for_rtl_languages_ &&
241 l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT);
242}
243
initial.commit09911bf2008-07-26 23:55:29244////////////////////////////////////////////////////////////////////////////////
245//
246// View - Right-to-left UI layout
247//
248////////////////////////////////////////////////////////////////////////////////
249
250inline int View::MirroredX() const {
[email protected]63329982008-10-10 21:56:57251 // TODO(beng): reimplement in terms of MirroredLeftPointForRect.
initial.commit09911bf2008-07-26 23:55:29252 View* parent = GetParent();
[email protected]80f8b9f2008-10-16 18:17:47253 if (parent && parent->UILayoutIsRightToLeft())
254 return parent->width() - x() - width();
255 return x();
initial.commit09911bf2008-07-26 23:55:29256}
257
258int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const {
259 if (!UILayoutIsRightToLeft()) {
260 return bounds.x();
261 }
[email protected]6f3bb6c2008-09-17 22:25:33262 return width() - bounds.x() - bounds.width();
initial.commit09911bf2008-07-26 23:55:29263}
264
265////////////////////////////////////////////////////////////////////////////////
266//
267// View - states
268//
269////////////////////////////////////////////////////////////////////////////////
270
271bool View::IsEnabled() const {
272 return enabled_;
273}
274
275void View::SetEnabled(bool state) {
276 if (enabled_ != state) {
277 enabled_ = state;
278 SchedulePaint();
279 }
280}
281
282bool View::IsFocusable() const {
283 return focusable_ && enabled_ && is_visible_;
284}
285
286void View::SetFocusable(bool focusable) {
287 focusable_ = focusable;
288}
289
290FocusManager* View::GetFocusManager() {
[email protected]4d0bd102008-10-16 00:26:30291 Container* container = GetContainer();
initial.commit09911bf2008-07-26 23:55:29292 if (!container)
293 return NULL;
294
295 HWND hwnd = container->GetHWND();
296 if (!hwnd)
297 return NULL;
298
[email protected]c2dacc92008-10-16 23:51:38299 return FocusManager::GetFocusManager(hwnd);
initial.commit09911bf2008-07-26 23:55:29300}
301
302bool View::HasFocus() {
303 RootView* root_view = GetRootView();
304 FocusManager* focus_manager = GetFocusManager();
305 if (focus_manager)
306 return focus_manager->GetFocusedView() == this;
307 return false;
308}
309
310void View::SetHotTracked(bool flag) {
311}
312
313/////////////////////////////////////////////////////////////////////////////
314//
315// View - painting
316//
317/////////////////////////////////////////////////////////////////////////////
318
[email protected]0a1d36b22008-10-17 19:33:09319void View::SchedulePaint(const gfx::Rect& r, bool urgent) {
320 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29321 return;
initial.commit09911bf2008-07-26 23:55:29322
323 if (parent_) {
324 // Translate the requested paint rect to the parent's coordinate system
325 // then pass this notification up to the parent.
[email protected]0a1d36b22008-10-17 19:33:09326 gfx::Rect paint_rect = r;
327 paint_rect.Offset(GetPosition());
initial.commit09911bf2008-07-26 23:55:29328 parent_->SchedulePaint(paint_rect, urgent);
329 }
330}
331
332void View::SchedulePaint() {
[email protected]0a1d36b22008-10-17 19:33:09333 SchedulePaint(GetLocalBounds(true), false);
initial.commit09911bf2008-07-26 23:55:29334}
335
336void View::SchedulePaint(int x, int y, int w, int h) {
[email protected]0a1d36b22008-10-17 19:33:09337 SchedulePaint(gfx::Rect(x, y, w, h), false);
initial.commit09911bf2008-07-26 23:55:29338}
339
340void View::Paint(ChromeCanvas* canvas) {
341 PaintBackground(canvas);
342 PaintFocusBorder(canvas);
343 PaintBorder(canvas);
344}
345
346void View::PaintBackground(ChromeCanvas* canvas) {
347 if (background_)
348 background_->Paint(canvas, this);
349}
350
351void View::PaintBorder(ChromeCanvas* canvas) {
352 if (border_)
353 border_->Paint(*this, canvas);
354}
355
356void View::PaintFocusBorder(ChromeCanvas* canvas) {
357 if (HasFocus() && IsFocusable())
[email protected]6f3bb6c2008-09-17 22:25:33358 canvas->DrawFocusRect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29359}
360
361void View::PaintChildren(ChromeCanvas* canvas) {
362 int i, c;
363 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
364 View* child = GetChildViewAt(i);
365 if (!child) {
366 NOTREACHED() << "Should not have a NULL child View for index in bounds";
367 continue;
368 }
369 child->ProcessPaint(canvas);
370 }
371}
372
373void View::ProcessPaint(ChromeCanvas* canvas) {
374 if (!IsVisible()) {
375 return;
376 }
377
378 // We're going to modify the canvas, save it's state first.
379 canvas->save();
380
381 // Paint this View and its children, setting the clip rect to the bounds
382 // of this View and translating the origin to the local bounds' top left
383 // point.
384 //
385 // Note that the X (or left) position we pass to ClipRectInt takes into
386 // consideration whether or not the view uses a right-to-left layout so that
387 // we paint our view in its mirrored position if need be.
[email protected]80f8b9f2008-10-16 18:17:47388 if (canvas->ClipRectInt(MirroredX(), y(), width(), height())) {
initial.commit09911bf2008-07-26 23:55:29389 // Non-empty clip, translate the graphics such that 0,0 corresponds to
390 // where this view is located (related to its parent).
[email protected]80f8b9f2008-10-16 18:17:47391 canvas->TranslateInt(MirroredX(), y());
initial.commit09911bf2008-07-26 23:55:29392
393 // Save the state again, so that any changes don't effect PaintChildren.
394 canvas->save();
395
396 // If the View we are about to paint requested the canvas to be flipped, we
397 // should change the transform appropriately.
398 bool flip_canvas = FlipCanvasOnPaintForRTLUI();
399 if (flip_canvas) {
[email protected]6f3bb6c2008-09-17 22:25:33400 canvas->TranslateInt(width(), 0);
initial.commit09911bf2008-07-26 23:55:29401 canvas->ScaleInt(-1, 1);
402 canvas->save();
403 }
404
405 Paint(canvas);
406
407 // We must undo the canvas mirroring once the View is done painting so that
408 // we don't pass the canvas with the mirrored transform to Views that
409 // didn't request the canvas to be flipped.
410 if (flip_canvas) {
411 canvas->restore();
412 }
413 canvas->restore();
414 PaintChildren(canvas);
415 }
416
417 // Restore the canvas's original transform.
418 canvas->restore();
419}
420
421void View::PaintNow() {
422 if (!IsVisible()) {
423 return;
424 }
425
426 View* view = GetParent();
427 if (view)
428 view->PaintNow();
429}
430
431void View::PaintFloatingView(ChromeCanvas* canvas, View* view,
432 int x, int y, int w, int h) {
433 if (should_restore_focus_ && ShouldRestoreFloatingViewFocus()) {
434 // We are painting again a floating view, this is a good time to restore the
435 // focus to the last focused floating view if any.
436 should_restore_focus_ = false;
437 restore_focus_view_task_ = new RestoreFocusTask(this);
438 MessageLoop::current()->PostTask(FROM_HERE, restore_focus_view_task_);
439 }
440 View* saved_parent = view->GetParent();
441 view->SetParent(this);
442 view->SetBounds(x, y, w, h);
443 view->Layout();
444 view->ProcessPaint(canvas);
445 view->SetParent(saved_parent);
446}
447
448void View::SetBackground(Background* b) {
449 if (background_ != b)
450 delete background_;
451 background_ = b;
452}
453
454const Background* View::GetBackground() const {
455 return background_;
456}
457
458void View::SetBorder(Border* b) {
459 if (border_ != b)
460 delete border_;
461 border_ = b;
462}
463
464const Border* View::GetBorder() const {
465 return border_;
466}
467
468gfx::Insets View::GetInsets() const {
469 const Border* border = GetBorder();
470 gfx::Insets insets;
471 if (border)
472 border->GetInsets(&insets);
473 return insets;
474}
475
476void View::SetContextMenuController(ContextMenuController* menu_controller) {
477 context_menu_controller_ = menu_controller;
478}
479
[email protected]042811c2008-10-31 21:31:34480void View::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
481 if (!context_menu_controller_)
482 return;
483
484 context_menu_controller_->ShowContextMenu(this, x, y, is_mouse_gesture);
485}
486
initial.commit09911bf2008-07-26 23:55:29487/////////////////////////////////////////////////////////////////////////////
488//
489// View - tree
490//
491/////////////////////////////////////////////////////////////////////////////
492
493bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
494 const bool enabled = enabled_;
495 int drag_operations;
[email protected]613b8062008-10-14 23:45:09496 if (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location()))
[email protected]6f3bb6c2008-09-17 22:25:33497 drag_operations = GetDragOperations(e.x(), e.y());
initial.commit09911bf2008-07-26 23:55:29498 else
499 drag_operations = 0;
500 ContextMenuController* context_menu_controller = context_menu_controller_;
501
502 const bool result = OnMousePressed(e);
503 // WARNING: we may have been deleted, don't use any View variables;
504
505 if (!enabled)
506 return result;
507
508 if (drag_operations != DragDropTypes::DRAG_NONE) {
[email protected]6f3bb6c2008-09-17 22:25:33509 drag_info->PossibleDrag(e.x(), e.y());
initial.commit09911bf2008-07-26 23:55:29510 return true;
511 }
512 return !!context_menu_controller || result;
513}
514
515bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
516 // Copy the field, that way if we're deleted after drag and drop no harm is
517 // done.
518 ContextMenuController* context_menu_controller = context_menu_controller_;
519 const bool possible_drag = drag_info->possible_drag;
[email protected]6f3bb6c2008-09-17 22:25:33520 if (possible_drag && ExceededDragThreshold(drag_info->start_x - e.x(),
521 drag_info->start_y - e.y())) {
initial.commit09911bf2008-07-26 23:55:29522 DoDrag(e, drag_info->start_x, drag_info->start_y);
523 } else {
524 if (OnMouseDragged(e))
525 return true;
526 // Fall through to return value based on context menu controller.
527 }
528 // WARNING: we may have been deleted.
529 return (context_menu_controller != NULL) || possible_drag;
530}
531
532void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
533 if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
534 // Assume that if there is a context menu controller we won't be deleted
535 // from mouse released.
[email protected]96b667d2008-10-14 20:58:44536 gfx::Point location(e.location());
initial.commit09911bf2008-07-26 23:55:29537 ConvertPointToScreen(this, &location);
538 ContextMenuController* context_menu_controller = context_menu_controller_;
539 OnMouseReleased(e, canceled);
[email protected]96b667d2008-10-14 20:58:44540 context_menu_controller_->ShowContextMenu(this, location.x(), location.y(),
initial.commit09911bf2008-07-26 23:55:29541 true);
542 } else {
543 OnMouseReleased(e, canceled);
544 }
545 // WARNING: we may have been deleted.
546}
547
548void View::DoDrag(const MouseEvent& e, int press_x, int press_y) {
549 scoped_refptr<OSExchangeData> data = new OSExchangeData;
550 WriteDragData(press_x, press_y, data.get());
551
552 // Message the RootView to do the drag and drop. That way if we're removed
[email protected]066e70a2008-10-24 01:55:03553 // the RootView can detect it and avoid calling us back.
initial.commit09911bf2008-07-26 23:55:29554 RootView* root_view = GetRootView();
555 root_view->StartDragForViewFromMouseEvent(
556 this, data, GetDragOperations(press_x, press_y));
557}
558
559void View::AddChildView(View* v) {
560 AddChildView(static_cast<int>(child_views_.size()), v, false);
561}
562
563void View::AddChildView(int index, View* v) {
564 AddChildView(index, v, false);
565}
566
567void View::AddChildView(int index, View* v, bool floating_view) {
568 // Remove the view from its current parent if any.
569 if (v->GetParent())
570 v->GetParent()->RemoveChildView(v);
571
572 if (!floating_view) {
573 // Sets the prev/next focus views.
574 InitFocusSiblings(v, index);
575 }
576
577 // Let's insert the view.
578 child_views_.insert(child_views_.begin() + index, v);
579 v->SetParent(this);
580
581 for (View* p = this; p; p = p->GetParent()) {
582 p->ViewHierarchyChangedImpl(false, true, this, v);
583 }
584 v->PropagateAddNotifications(this, v);
585 UpdateTooltip();
586 RootView* root = GetRootView();
587 if (root)
588 RegisterChildrenForVisibleBoundsNotification(root, v);
589
590 if (layout_manager_.get())
591 layout_manager_->ViewAdded(this, v);
592}
593
594View* View::GetChildViewAt(int index) const {
595 return index < GetChildViewCount() ? child_views_[index] : NULL;
596}
597
598int View::GetChildViewCount() const {
599 return static_cast<int>(child_views_.size());
600}
601
602void View::RemoveChildView(View* a_view) {
603 DoRemoveChildView(a_view, true, true, false);
604}
605
606void View::RemoveAllChildViews(bool delete_views) {
607 ViewList::iterator iter;
608 while ((iter = child_views_.begin()) != child_views_.end()) {
609 DoRemoveChildView(*iter, false, false, delete_views);
610 }
611 UpdateTooltip();
612}
613
614void View::DoRemoveChildView(View* a_view,
615 bool update_focus_cycle,
616 bool update_tool_tip,
617 bool delete_removed_view) {
618#ifndef NDEBUG
619 DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
620 "during a paint, this will seriously " <<
621 "mess things up!";
622#endif
623 DCHECK(a_view);
624 const ViewList::iterator i = find(child_views_.begin(),
625 child_views_.end(),
626 a_view);
627 if (i != child_views_.end()) {
628 if (update_focus_cycle && !a_view->IsFloatingView()) {
629 // Let's remove the view from the focus traversal.
630 View* next_focusable = a_view->next_focusable_view_;
631 View* prev_focusable = a_view->previous_focusable_view_;
632 if (prev_focusable)
633 prev_focusable->next_focusable_view_ = next_focusable;
634 if (next_focusable)
635 next_focusable->previous_focusable_view_ = prev_focusable;
636 }
637
638 RootView* root = GetRootView();
639 if (root)
640 UnregisterChildrenForVisibleBoundsNotification(root, a_view);
641 a_view->PropagateRemoveNotifications(this);
642 a_view->SetParent(NULL);
643
644 if (delete_removed_view && a_view->IsParentOwned())
645 delete a_view;
646
647 child_views_.erase(i);
648 }
649
650 if (update_tool_tip)
651 UpdateTooltip();
652
653 if (layout_manager_.get())
654 layout_manager_->ViewRemoved(this, a_view);
655}
656
657void View::PropagateRemoveNotifications(View* parent) {
658 int i, c;
659 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
660 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
661 }
662
663 View *t;
664 for (t = this; t; t = t->GetParent()) {
665 t->ViewHierarchyChangedImpl(true, false, parent, this);
666 }
667}
668
669void View::PropagateAddNotifications(View* parent, View* child) {
670 int i, c;
671 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
672 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
673 }
674 ViewHierarchyChangedImpl(true, true, parent, child);
675}
676
677#ifndef NDEBUG
678bool View::IsProcessingPaint() const {
679 return GetParent() && GetParent()->IsProcessingPaint();
680}
681#endif
682
[email protected]82739cf2008-09-16 00:37:56683bool View::HasHitTestMask() const {
684 return false;
685}
686
687void View::GetHitTestMask(gfx::Path* mask) const {
688 DCHECK(mask);
689}
690
initial.commit09911bf2008-07-26 23:55:29691void View::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
692}
693
694void View::ViewHierarchyChangedImpl(bool register_accelerators,
695 bool is_add, View *parent, View *child) {
696 if (register_accelerators) {
697 if (is_add) {
698 // If you get this registration, you are part of a subtree that has been
699 // added to the view hierarchy.
700 RegisterAccelerators();
701 } else {
702 if (child == this)
703 UnregisterAccelerators();
704 }
705 }
706
707 ViewHierarchyChanged(is_add, parent, child);
708}
709
710void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
711 int i, c;
712 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
713 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
714 }
715 VisibilityChanged(start, is_visible);
716}
717
718void View::VisibilityChanged(View* starting_from, bool is_visible) {
719}
720
[email protected]613b8062008-10-14 23:45:09721View* View::GetViewForPoint(const gfx::Point& point) {
initial.commit09911bf2008-07-26 23:55:29722 return GetViewForPoint(point, true);
723}
724
725void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
726 if (notify_when_visible_bounds_in_root_changes_ == value)
727 return;
728 notify_when_visible_bounds_in_root_changes_ = value;
729 RootView* root = GetRootView();
730 if (root) {
731 if (value)
732 root->RegisterViewForVisibleBoundsNotification(this);
733 else
734 root->UnregisterViewForVisibleBoundsNotification(this);
735 }
736}
737
738bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
739 return notify_when_visible_bounds_in_root_changes_;
740}
741
[email protected]613b8062008-10-14 23:45:09742View* View::GetViewForPoint(const gfx::Point& point,
743 bool can_create_floating) {
initial.commit09911bf2008-07-26 23:55:29744 // Walk the child Views recursively looking for the View that most
745 // tightly encloses the specified point.
746 for (int i = GetChildViewCount() - 1 ; i >= 0 ; --i) {
747 View* child = GetChildViewAt(i);
[email protected]82739cf2008-09-16 00:37:56748 if (!child->IsVisible())
initial.commit09911bf2008-07-26 23:55:29749 continue;
[email protected]82739cf2008-09-16 00:37:56750
[email protected]96b667d2008-10-14 20:58:44751 gfx::Point point_in_child_coords(point);
[email protected]82739cf2008-09-16 00:37:56752 View::ConvertPointToView(this, child, &point_in_child_coords);
[email protected]613b8062008-10-14 23:45:09753 if (child->HitTest(point_in_child_coords))
754 return child->GetViewForPoint(point_in_child_coords, true);
initial.commit09911bf2008-07-26 23:55:29755 }
756
757 // We haven't found a view for the point. Try to create floating views
758 // and try again if one was created.
759 // can_create_floating makes sure we don't try forever even if
760 // GetFloatingViewIDForPoint lies or if RetrieveFloatingViewForID creates a
761 // view which doesn't contain the provided point
762 int id;
[email protected]613b8062008-10-14 23:45:09763 if (can_create_floating &&
764 GetFloatingViewIDForPoint(point.x(), point.y(), &id)) {
initial.commit09911bf2008-07-26 23:55:29765 RetrieveFloatingViewForID(id); // This creates the floating view.
766 return GetViewForPoint(point, false);
767 }
768 return this;
769}
770
[email protected]4d0bd102008-10-16 00:26:30771Container* View::GetContainer() const {
initial.commit09911bf2008-07-26 23:55:29772 // The root view holds a reference to this view hierarchy's container.
[email protected]4d0bd102008-10-16 00:26:30773 return parent_ ? parent_->GetContainer() : NULL;
initial.commit09911bf2008-07-26 23:55:29774}
775
776// Get the containing RootView
777RootView* View::GetRootView() {
[email protected]4d0bd102008-10-16 00:26:30778 Container* vc = GetContainer();
initial.commit09911bf2008-07-26 23:55:29779 if (vc) {
780 return vc->GetRootView();
781 } else {
782 return NULL;
783 }
784}
785
786View* View::GetViewByID(int id) const {
787 if (id == id_)
788 return const_cast<View*>(this);
789
790 int view_count = GetChildViewCount();
791 for (int i = 0; i < view_count; ++i) {
792 View* child = GetChildViewAt(i);
793 View* view = child->GetViewByID(id);
794 if (view)
795 return view;
796 }
797 return NULL;
798}
799
800void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
801 if (group_ == group_id)
802 out->push_back(this);
803
804 int view_count = GetChildViewCount();
805 for (int i = 0; i < view_count; ++i)
806 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
807}
808
809View* View::GetSelectedViewForGroup(int group_id) {
810 std::vector<View*> views;
811 GetRootView()->GetViewsWithGroup(group_id, &views);
812 if (views.size() > 0)
813 return views[0];
814 else
815 return NULL;
816}
817
818void View::SetID(int id) {
819 id_ = id;
820}
821
822int View::GetID() const {
823 return id_;
824}
825
826void View::SetGroup(int gid) {
827 group_ = gid;
828}
829
830int View::GetGroup() const {
831 return group_;
832}
833
834void View::SetParent(View* parent) {
835 if (parent != parent_) {
836 parent_ = parent;
837 }
838}
839
840bool View::IsParentOf(View* v) const {
841 DCHECK(v);
842 View* parent = v->GetParent();
843 while (parent) {
844 if (this == parent)
845 return true;
846 parent = parent->GetParent();
847 }
848 return false;
849}
850
851int View::GetChildIndex(View* v) const {
852 for (int i = 0; i < GetChildViewCount(); i++) {
853 if (v == GetChildViewAt(i))
854 return i;
855 }
856 return -1;
857}
858
859///////////////////////////////////////////////////////////////////////////////
860//
861// View - focus
862//
863///////////////////////////////////////////////////////////////////////////////
864
865View* View::GetNextFocusableView() {
866 return next_focusable_view_;
867}
868
869View* View::GetPreviousFocusableView() {
870 return previous_focusable_view_;
871}
872
873void View::SetNextFocusableView(View* view) {
874 view->previous_focusable_view_ = this;
875 next_focusable_view_ = view;
876}
877
878void View::InitFocusSiblings(View* v, int index) {
879 int child_count = static_cast<int>(child_views_.size());
880
881 if (child_count == 0) {
882 v->next_focusable_view_ = NULL;
883 v->previous_focusable_view_ = NULL;
884 } else {
885 if (index == child_count) {
886 // We are inserting at the end, but the end of the child list may not be
887 // the last focusable element. Let's try to find an element with no next
888 // focusable element to link to.
889 View* last_focusable_view = NULL;
890 for (std::vector<View*>::iterator iter = child_views_.begin();
891 iter != child_views_.end(); ++iter) {
892 if (!(*iter)->next_focusable_view_) {
893 last_focusable_view = *iter;
894 break;
895 }
896 }
897 if (last_focusable_view == NULL) {
898 // Hum... there is a cycle in the focus list. Let's just insert ourself
899 // after the last child.
900 View* prev = child_views_[index - 1];
901 v->previous_focusable_view_ = prev;
902 v->next_focusable_view_ = prev->next_focusable_view_;
903 prev->next_focusable_view_->previous_focusable_view_ = v;
904 prev->next_focusable_view_ = v;
905 } else {
906 last_focusable_view->next_focusable_view_ = v;
907 v->next_focusable_view_ = NULL;
908 v->previous_focusable_view_ = last_focusable_view;
909 }
910 } else {
911 View* prev = child_views_[index]->GetPreviousFocusableView();
912 v->previous_focusable_view_ = prev;
913 v->next_focusable_view_ = child_views_[index];
914 if (prev)
915 prev->next_focusable_view_ = v;
916 child_views_[index]->previous_focusable_view_ = v;
917 }
918 }
919}
920
921#ifndef NDEBUG
922void View::PrintViewHierarchy() {
923 PrintViewHierarchyImp(0);
924}
925
926void View::PrintViewHierarchyImp(int indent) {
927 std::wostringstream buf;
928 int ind = indent;
929 while (ind-- > 0)
930 buf << L' ';
931 buf << UTF8ToWide(GetClassName());
932 buf << L' ';
933 buf << GetID();
934 buf << L' ';
[email protected]80f8b9f2008-10-16 18:17:47935 buf << bounds_.x() << L"," << bounds_.y() << L",";
936 buf << bounds_.right() << L"," << bounds_.bottom();
initial.commit09911bf2008-07-26 23:55:29937 buf << L' ';
938 buf << this;
939
940 LOG(INFO) << buf.str();
941 std::cout << buf.str() << std::endl;
942
943 for (int i = 0; i < GetChildViewCount(); ++i) {
944 GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
945 }
946}
947
948
949void View::PrintFocusHierarchy() {
950 PrintFocusHierarchyImp(0);
951}
952
953void View::PrintFocusHierarchyImp(int indent) {
954 std::wostringstream buf;
955 int ind = indent;
956 while (ind-- > 0)
957 buf << L' ';
958 buf << UTF8ToWide(GetClassName());
959 buf << L' ';
960 buf << GetID();
961 buf << L' ';
962 buf << GetClassName().c_str();
963 buf << L' ';
964 buf << this;
965
966 LOG(INFO) << buf.str();
967 std::cout << buf.str() << std::endl;
968
969 if (GetChildViewCount() > 0)
970 GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
971
972 View* v = GetNextFocusableView();
973 if (v)
974 v->PrintFocusHierarchyImp(indent);
975}
976#endif
977
978////////////////////////////////////////////////////////////////////////////////
979//
980// View - accelerators
981//
982////////////////////////////////////////////////////////////////////////////////
983
984void View::AddAccelerator(const Accelerator& accelerator) {
985 if (!accelerators_.get())
986 accelerators_.reset(new std::vector<Accelerator>());
987 accelerators_->push_back(accelerator);
988 RegisterAccelerators();
989}
990
[email protected]e8e0f362008-11-08 01:13:25991void View::RemoveAccelerator(const Accelerator& accelerator) {
992 std::vector<Accelerator>::iterator iter;
993 if (!accelerators_.get() ||
994 ((iter = std::find(accelerators_->begin(), accelerators_->end(),
995 accelerator)) == accelerators_->end())) {
996 NOTREACHED() << "Removing non-existing accelerator";
997 return;
998 }
999
1000 accelerators_->erase(iter);
1001 RootView* root_view = GetRootView();
1002 if (!root_view) {
1003 // We are not part of a view hierarchy, so there is nothing to do as we
1004 // removed ourselves from accelerators_, we won't be registered when added
1005 // to one.
1006 return;
1007 }
1008
1009 FocusManager* focus_manager = GetFocusManager();
1010 if (focus_manager) {
1011 // We may not have a FocusManager if the window containing us is being
1012 // closed, in which case the FocusManager is being deleted so there is
1013 // nothing to unregister.
1014 focus_manager->UnregisterAccelerator(accelerator, this);
1015 }
1016}
1017
initial.commit09911bf2008-07-26 23:55:291018void View::ResetAccelerators() {
1019 if (accelerators_.get()) {
1020 UnregisterAccelerators();
1021 accelerators_->clear();
1022 accelerators_.reset();
1023 }
1024}
1025
1026void View::RegisterAccelerators() {
1027 if (!accelerators_.get())
1028 return;
1029
1030 RootView* root_view = GetRootView();
1031 if (!root_view) {
1032 // We are not yet part of a view hierarchy, we'll register ourselves once
1033 // added to one.
1034 return;
1035 }
1036 FocusManager* focus_manager = GetFocusManager();
1037 if (!focus_manager) {
1038 // Some crash reports seem to show that we may get cases where we have no
1039 // focus manager (see bug #1291225). This should never be the case, just
1040 // making sure we don't crash.
1041 NOTREACHED();
1042 return;
1043 }
1044 for (std::vector<Accelerator>::const_iterator iter = accelerators_->begin();
1045 iter != accelerators_->end(); ++iter) {
1046 focus_manager->RegisterAccelerator(*iter, this);
1047 }
1048}
1049
1050void View::UnregisterAccelerators() {
1051 if (!accelerators_.get())
1052 return;
1053
1054 RootView* root_view = GetRootView();
1055 if (root_view) {
1056 FocusManager* focus_manager = GetFocusManager();
1057 if (focus_manager) {
1058 // We may not have a FocusManager if the window containing us is being
1059 // closed, in which case the FocusManager is being deleted so there is
1060 // nothing to unregister.
1061 focus_manager->UnregisterAccelerators(this);
1062 }
1063 }
1064}
1065
1066/////////////////////////////////////////////////////////////////////////////
1067//
1068// View - accessibility
1069//
1070/////////////////////////////////////////////////////////////////////////////
1071
1072AccessibleWrapper* View::GetAccessibleWrapper() {
1073 if (accessibility_.get() == NULL) {
1074 accessibility_.reset(new AccessibleWrapper(this));
1075 }
1076 return accessibility_.get();
1077}
1078
1079/////////////////////////////////////////////////////////////////////////////
1080//
1081// View - floating views
1082//
1083/////////////////////////////////////////////////////////////////////////////
1084
1085bool View::IsFloatingView() {
1086 if (!parent_)
1087 return false;
1088
1089 return parent_->floating_views_ids_.find(this) !=
1090 parent_->floating_views_ids_.end();
1091}
1092
1093// default implementation does nothing
1094bool View::GetFloatingViewIDForPoint(int x, int y, int* id) {
1095 return false;
1096}
1097
1098int View::GetFloatingViewCount() const {
1099 return static_cast<int>(floating_views_.size());
1100}
1101
1102View* View::RetrieveFloatingViewParent() {
1103 View* v = this;
1104 while (v) {
1105 if (v->IsFloatingView())
1106 return v;
1107 v = v->GetParent();
1108 }
1109 return NULL;
1110}
1111
1112bool View::EnumerateFloatingViews(FloatingViewPosition position,
1113 int starting_id, int* id) {
1114 return false;
1115}
1116
1117int View::GetDragOperations(int press_x, int press_y) {
1118 if (!drag_controller_)
1119 return DragDropTypes::DRAG_NONE;
1120 return drag_controller_->GetDragOperations(this, press_x, press_y);
1121}
1122
1123void View::WriteDragData(int press_x, int press_y, OSExchangeData* data) {
1124 DCHECK(drag_controller_);
1125 drag_controller_->WriteDragData(this, press_x, press_y, data);
1126}
1127
1128void View::OnDragDone() {
1129}
1130
1131bool View::InDrag() {
1132 RootView* root_view = GetRootView();
1133 return root_view ? (root_view->GetDragView() == this) : false;
1134}
1135
1136View* View::ValidateFloatingViewForID(int id) {
1137 return NULL;
1138}
1139
1140bool View::ShouldRestoreFloatingViewFocus() {
1141 return true;
1142}
1143
1144void View::AttachFloatingView(View* v, int id) {
1145 floating_views_.push_back(v);
1146 floating_views_ids_[v] = id;
1147 AddChildView(static_cast<int>(child_views_.size()), v, true);
1148}
1149
1150bool View::HasFloatingViewForPoint(int x, int y) {
1151 int i, c;
1152 View* v;
1153 gfx::Rect r;
1154
1155 for (i = 0, c = static_cast<int>(floating_views_.size()); i < c; ++i) {
1156 v = floating_views_[i];
[email protected]6f3bb6c2008-09-17 22:25:331157 r.SetRect(v->GetX(APPLY_MIRRORING_TRANSFORMATION), v->y(),
1158 v->width(), v->height());
initial.commit09911bf2008-07-26 23:55:291159 if (r.Contains(x, y))
1160 return true;
1161 }
1162 return false;
1163}
1164
1165void View::DetachAllFloatingViews() {
1166 RootView* root_view = GetRootView();
1167 View* focused_view = NULL;
1168 FocusManager* focus_manager = NULL;
1169 if (root_view) {
1170 // We may be called when we are not attached to a root view in which case
1171 // there is nothing to do for focus.
1172 focus_manager = GetFocusManager();
1173 if (focus_manager) {
1174 // We may not have a focus manager (if we are detached from a top window).
1175 focused_view = focus_manager->GetFocusedView();
1176 }
1177 }
1178
1179 int c = static_cast<int>(floating_views_.size());
1180 while (--c >= 0) {
1181 // If the focused view is a floating view or a floating view's children,
1182 // use the focus manager to store it.
1183 int tmp_id;
1184 if (focused_view &&
1185 ((focused_view == floating_views_[c]) ||
1186 floating_views_[c]->IsParentOf(focused_view))) {
1187 // We call EnumerateFloatingView to make sure the floating view is still
1188 // valid: the model may have changed and could not know anything about
1189 // that floating view anymore.
1190 if (EnumerateFloatingViews(CURRENT,
1191 floating_views_[c]->GetFloatingViewID(),
1192 &tmp_id)) {
1193 focus_manager->StoreFocusedView();
1194 should_restore_focus_ = true;
1195 }
1196 focused_view = NULL;
1197 }
1198
1199 RemoveChildView(floating_views_[c]);
1200 delete floating_views_[c];
1201 }
1202 floating_views_.clear();
1203 floating_views_ids_.clear();
1204}
1205
1206int View::GetFloatingViewID() {
1207 DCHECK(IsFloatingView());
1208 std::map<View*, int>::iterator iter = parent_->floating_views_ids_.find(this);
1209 DCHECK(iter != parent_->floating_views_ids_.end());
1210 return iter->second;
1211}
1212
1213View* View::RetrieveFloatingViewForID(int id) {
1214 for (ViewList::const_iterator iter = floating_views_.begin();
1215 iter != floating_views_.end(); ++iter) {
1216 if ((*iter)->GetFloatingViewID() == id)
1217 return *iter;
1218 }
1219 return ValidateFloatingViewForID(id);
1220}
1221
1222void View::RestoreFloatingViewFocus() {
1223 // Clear the reference to the task as if we have been triggered by it, it will
1224 // soon be invalid.
1225 restore_focus_view_task_ = NULL;
1226 should_restore_focus_ = false;
1227
1228 GetFocusManager()->RestoreFocusedView();
1229}
1230
1231// static
1232bool View::EnumerateFloatingViewsForInterval(int low_bound, int high_bound,
1233 bool ascending_order,
1234 FloatingViewPosition position,
1235 int starting_id,
1236 int* id) {
1237 DCHECK(low_bound <= high_bound);
1238 if (low_bound >= high_bound)
1239 return false;
1240
1241 switch (position) {
1242 case CURRENT:
1243 if ((starting_id >= low_bound) && (starting_id < high_bound)) {
1244 *id = starting_id;
1245 return true;
1246 }
1247 return false;
1248 case FIRST:
1249 *id = ascending_order ? low_bound : high_bound - 1;
1250 return true;
1251 case LAST:
1252 *id = ascending_order ? high_bound - 1 : low_bound;
1253 return true;
1254 case NEXT:
1255 case PREVIOUS:
1256 if (((position == NEXT) && ascending_order) ||
1257 ((position == PREVIOUS) && !ascending_order)) {
1258 starting_id++;
1259 if (starting_id < high_bound) {
1260 *id = starting_id;
1261 return true;
1262 }
1263 return false;
1264 }
1265 DCHECK(((position == NEXT) && !ascending_order) ||
1266 ((position == PREVIOUS) && ascending_order));
1267 starting_id--;
1268 if (starting_id >= low_bound) {
1269 *id = starting_id;
1270 return true;
1271 }
1272 return false;
1273 default:
1274 NOTREACHED();
1275 }
1276 return false;
1277}
1278
1279// static
[email protected]96b667d2008-10-14 20:58:441280void View::ConvertPointToView(View* src, View* dst, gfx::Point* point) {
initial.commit09911bf2008-07-26 23:55:291281 ConvertPointToView(src, dst, point, true);
1282}
1283
1284// static
[email protected]96b667d2008-10-14 20:58:441285void View::ConvertPointToView(View* src, View* dst, gfx::Point* point,
initial.commit09911bf2008-07-26 23:55:291286 bool try_other_direction) {
1287 // src can be NULL
1288 DCHECK(dst);
1289 DCHECK(point);
1290
1291 View* v;
1292 gfx::Point offset;
1293
1294 for (v = dst; v && v != src; v = v->GetParent()) {
1295 offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
[email protected]6f3bb6c2008-09-17 22:25:331296 offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291297 }
1298
1299 // The source was not found. The caller wants a conversion
1300 // from a view to a transitive parent.
1301 if (src && v == NULL && try_other_direction) {
1302 gfx::Point p;
1303 // note: try_other_direction is force to FALSE so we don't
1304 // end up in an infinite recursion should both src and dst
1305 // are not parented.
1306 ConvertPointToView(dst, src, &p, false);
1307 // since the src and dst are inverted, p should also be negated
1308 point->SetPoint(point->x() - p.x(), point->y() - p.y());
1309 } else {
1310 point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
1311
1312 // If src is NULL, sp is in the screen coordinate system
1313 if (src == NULL) {
[email protected]4d0bd102008-10-16 00:26:301314 Container* vc = dst->GetContainer();
initial.commit09911bf2008-07-26 23:55:291315 if (vc) {
1316 CRect b;
1317 vc->GetBounds(&b, false);
1318 point->SetPoint(point->x() - b.left, point->y() - b.top);
1319 }
1320 }
1321 }
1322}
1323
1324// static
[email protected]4d0bd102008-10-16 00:26:301325void View::ConvertPointToContainer(View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291326 DCHECK(src);
1327 DCHECK(p);
[email protected]96b667d2008-10-14 20:58:441328
initial.commit09911bf2008-07-26 23:55:291329 View *v;
[email protected]96b667d2008-10-14 20:58:441330 gfx::Point offset;
initial.commit09911bf2008-07-26 23:55:291331 for (v = src; v; v = v->GetParent()) {
[email protected]96b667d2008-10-14 20:58:441332 offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION));
1333 offset.set_y(offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291334 }
[email protected]96b667d2008-10-14 20:58:441335 p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
initial.commit09911bf2008-07-26 23:55:291336}
1337
1338// static
[email protected]4d0bd102008-10-16 00:26:301339void View::ConvertPointFromContainer(View *source, gfx::Point* p) {
[email protected]96b667d2008-10-14 20:58:441340 gfx::Point t;
[email protected]4d0bd102008-10-16 00:26:301341 ConvertPointToContainer(source, &t);
[email protected]96b667d2008-10-14 20:58:441342 p->SetPoint(p->x() - t.x(), p->y() - t.y());
initial.commit09911bf2008-07-26 23:55:291343}
1344
1345// static
[email protected]96b667d2008-10-14 20:58:441346void View::ConvertPointToScreen(View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291347 DCHECK(src);
1348 DCHECK(p);
1349
[email protected]96b667d2008-10-14 20:58:441350 // If the view is not connected to a tree, there's nothing we can do.
[email protected]4d0bd102008-10-16 00:26:301351 Container* vc = src->GetContainer();
initial.commit09911bf2008-07-26 23:55:291352 if (vc) {
[email protected]4d0bd102008-10-16 00:26:301353 ConvertPointToContainer(src, p);
initial.commit09911bf2008-07-26 23:55:291354 CRect r;
1355 vc->GetBounds(&r, false);
[email protected]96b667d2008-10-14 20:58:441356 p->SetPoint(p->x() + r.left, p->y() + r.top);
initial.commit09911bf2008-07-26 23:55:291357 }
1358}
1359
1360/////////////////////////////////////////////////////////////////////////////
1361//
1362// View - event handlers
1363//
1364/////////////////////////////////////////////////////////////////////////////
1365
1366bool View::OnMousePressed(const MouseEvent& e) {
1367 return false;
1368}
1369
1370bool View::OnMouseDragged(const MouseEvent& e) {
1371 return false;
1372}
1373
1374void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
1375}
1376
1377void View::OnMouseMoved(const MouseEvent& e) {
1378}
1379
1380void View::OnMouseEntered(const MouseEvent& e) {
1381}
1382
1383void View::OnMouseExited(const MouseEvent& e) {
1384}
1385
1386void View::SetMouseHandler(View *new_mouse_handler) {
1387 // It is valid for new_mouse_handler to be NULL
1388 if (parent_) {
1389 parent_->SetMouseHandler(new_mouse_handler);
1390 }
1391}
1392
1393void View::SetVisible(bool flag) {
1394 if (flag != is_visible_) {
1395 // If the tab is currently visible, schedule paint to
1396 // refresh parent
1397 if (IsVisible()) {
1398 SchedulePaint();
1399 }
1400
1401 is_visible_ = flag;
1402
1403 // This notifies all subviews recursively.
1404 PropagateVisibilityNotifications(this, flag);
1405
1406 // If we are newly visible, schedule paint.
1407 if (IsVisible()) {
1408 SchedulePaint();
1409 }
1410 }
1411}
1412
1413bool View::IsVisibleInRootView() const {
1414 View* parent = GetParent();
1415 if (IsVisible() && parent)
1416 return parent->IsVisibleInRootView();
1417 else
1418 return false;
1419}
1420
[email protected]613b8062008-10-14 23:45:091421bool View::HitTest(const gfx::Point& l) const {
1422 if (l.x() >= 0 && l.x() < static_cast<int>(width()) &&
1423 l.y() >= 0 && l.y() < static_cast<int>(height())) {
[email protected]82739cf2008-09-16 00:37:561424 if (HasHitTestMask()) {
1425 gfx::Path mask;
1426 GetHitTestMask(&mask);
1427 ScopedHRGN rgn(mask.CreateHRGN());
[email protected]613b8062008-10-14 23:45:091428 return !!PtInRegion(rgn, l.x(), l.y());
[email protected]82739cf2008-09-16 00:37:561429 }
1430 // No mask, but inside our bounds.
initial.commit09911bf2008-07-26 23:55:291431 return true;
initial.commit09911bf2008-07-26 23:55:291432 }
[email protected]82739cf2008-09-16 00:37:561433 // Outside our bounds.
1434 return false;
initial.commit09911bf2008-07-26 23:55:291435}
1436
1437HCURSOR View::GetCursorForPoint(Event::EventType event_type, int x, int y) {
1438 return NULL;
1439}
1440
1441/////////////////////////////////////////////////////////////////////////////
1442//
1443// View - keyboard and focus
1444//
1445/////////////////////////////////////////////////////////////////////////////
1446
1447void View::RequestFocus() {
1448 RootView* rv = GetRootView();
1449 if (rv) {
1450 rv->FocusView(this);
1451 }
1452}
1453
1454void View::WillGainFocus() {
1455}
1456
1457void View::DidGainFocus() {
1458}
1459
1460void View::WillLoseFocus() {
1461}
1462
1463bool View::OnKeyPressed(const KeyEvent& e) {
1464 return false;
1465}
1466
1467bool View::OnKeyReleased(const KeyEvent& e) {
1468 return false;
1469}
1470
1471bool View::OnMouseWheel(const MouseWheelEvent& e) {
1472 return false;
1473}
1474
1475void View::SetDragController(DragController* drag_controller) {
1476 drag_controller_ = drag_controller;
1477}
1478
1479DragController* View::GetDragController() {
1480 return drag_controller_;
1481}
1482
1483bool View::CanDrop(const OSExchangeData& data) {
1484 return false;
1485}
1486
1487void View::OnDragEntered(const DropTargetEvent& event) {
1488}
1489
1490int View::OnDragUpdated(const DropTargetEvent& event) {
1491 return DragDropTypes::DRAG_NONE;
1492}
1493
1494void View::OnDragExited() {
1495}
1496
1497int View::OnPerformDrop(const DropTargetEvent& event) {
1498 return DragDropTypes::DRAG_NONE;
1499}
1500
1501static int GetHorizontalDragThreshold() {
1502 static int threshold = -1;
1503 if (threshold == -1)
1504 threshold = GetSystemMetrics(SM_CXDRAG) / 2;
1505 return threshold;
1506}
1507
1508static int GetVerticalDragThreshold() {
1509 static int threshold = -1;
1510 if (threshold == -1)
1511 threshold = GetSystemMetrics(SM_CYDRAG) / 2;
1512 return threshold;
1513}
1514
1515// static
1516bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1517 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1518 abs(delta_y) > GetVerticalDragThreshold());
1519}
1520
1521void View::Focus() {
1522 // Set the native focus to the root view window so it receives the keyboard
1523 // messages.
1524 FocusManager* focus_manager = GetFocusManager();
1525 if (focus_manager)
[email protected]4d0bd102008-10-16 00:26:301526 focus_manager->FocusHWND(GetRootView()->GetContainer()->GetHWND());
initial.commit09911bf2008-07-26 23:55:291527}
1528
1529bool View::CanProcessTabKeyEvents() {
1530 return false;
1531}
1532
1533// Tooltips -----------------------------------------------------------------
1534bool View::GetTooltipText(int x, int y, std::wstring* tooltip) {
1535 return false;
1536}
1537
[email protected]0a1d36b22008-10-17 19:33:091538bool View::GetTooltipTextOrigin(int x, int y, gfx::Point* loc) {
initial.commit09911bf2008-07-26 23:55:291539 return false;
1540}
1541
1542void View::TooltipTextChanged() {
[email protected]4d0bd102008-10-16 00:26:301543 Container* view_container = GetContainer();
initial.commit09911bf2008-07-26 23:55:291544 if (view_container != NULL && view_container->GetTooltipManager())
1545 view_container->GetTooltipManager()->TooltipTextChanged(this);
1546}
1547
1548void View::UpdateTooltip() {
[email protected]4d0bd102008-10-16 00:26:301549 Container* view_container = GetContainer();
initial.commit09911bf2008-07-26 23:55:291550 if (view_container != NULL && view_container->GetTooltipManager())
1551 view_container->GetTooltipManager()->UpdateTooltip();
1552}
1553
1554void View::SetParentOwned(bool f) {
1555 is_parent_owned_ = f;
1556}
1557
1558bool View::IsParentOwned() const {
1559 return is_parent_owned_;
1560}
1561
1562std::string View::GetClassName() const {
1563 return kViewClassName;
1564}
1565
1566gfx::Rect View::GetVisibleBounds() {
[email protected]6f3bb6c2008-09-17 22:25:331567 gfx::Rect vis_bounds(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:291568 gfx::Rect ancestor_bounds;
1569 View* view = this;
1570 int root_x = 0;
1571 int root_y = 0;
1572 bool has_view_container = false;
1573 while (view != NULL && !vis_bounds.IsEmpty()) {
1574 root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
[email protected]6f3bb6c2008-09-17 22:25:331575 root_y += view->y();
1576 vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y());
initial.commit09911bf2008-07-26 23:55:291577 View* ancestor = view->GetParent();
1578 if (ancestor != NULL) {
[email protected]6f3bb6c2008-09-17 22:25:331579 ancestor_bounds.SetRect(0, 0, ancestor->width(),
1580 ancestor->height());
initial.commit09911bf2008-07-26 23:55:291581 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
[email protected]4d0bd102008-10-16 00:26:301582 } else if (!view->GetContainer()) {
1583 // If the view has no Container, we're not visible. Return an empty
initial.commit09911bf2008-07-26 23:55:291584 // rect.
1585 return gfx::Rect();
1586 }
1587 view = ancestor;
1588 }
1589 if (vis_bounds.IsEmpty())
1590 return vis_bounds;
1591 // Convert back to this views coordinate system.
1592 vis_bounds.Offset(-root_x, -root_y);
1593 return vis_bounds;
1594}
1595
1596int View::GetPageScrollIncrement(ScrollView* scroll_view,
1597 bool is_horizontal, bool is_positive) {
1598 return 0;
1599}
1600
1601int View::GetLineScrollIncrement(ScrollView* scroll_view,
1602 bool is_horizontal, bool is_positive) {
1603 return 0;
1604}
1605
1606// static
1607void View::RegisterChildrenForVisibleBoundsNotification(
1608 RootView* root, View* view) {
1609 DCHECK(root && view);
1610 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1611 root->RegisterViewForVisibleBoundsNotification(view);
1612 for (int i = 0; i < view->GetChildViewCount(); ++i)
1613 RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i));
1614}
1615
1616// static
1617void View::UnregisterChildrenForVisibleBoundsNotification(
1618 RootView* root, View* view) {
1619 DCHECK(root && view);
1620 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1621 root->UnregisterViewForVisibleBoundsNotification(view);
1622 for (int i = 0; i < view->GetChildViewCount(); ++i)
1623 UnregisterChildrenForVisibleBoundsNotification(root,
1624 view->GetChildViewAt(i));
1625}
1626
1627void View::AddDescendantToNotify(View* view) {
1628 DCHECK(view);
1629 if (!descendants_to_notify_.get())
1630 descendants_to_notify_.reset(new ViewList());
1631 descendants_to_notify_->push_back(view);
1632}
1633
1634void View::RemoveDescendantToNotify(View* view) {
1635 DCHECK(view && descendants_to_notify_.get());
1636 ViewList::iterator i = find(descendants_to_notify_->begin(),
1637 descendants_to_notify_->end(),
1638 view);
1639 DCHECK(i != descendants_to_notify_->end());
1640 descendants_to_notify_->erase(i);
1641 if (descendants_to_notify_->empty())
1642 descendants_to_notify_.reset();
1643}
1644
1645// static
1646bool View::GetViewPath(View* start, View* end, std::vector<int>* path) {
1647 while (end && (end != start)) {
1648 View* parent = end->GetParent();
1649 if (!parent)
1650 return false;
1651 path->insert(path->begin(), parent->GetChildIndex(end));
1652 end = parent;
1653 }
1654 return end == start;
1655}
1656
1657// static
1658View* View::GetViewForPath(View* start, const std::vector<int>& path) {
1659 View* v = start;
1660 for (std::vector<int>::const_iterator iter = path.begin();
1661 iter != path.end(); ++iter) {
1662 int index = *iter;
1663 if (index >= v->GetChildViewCount())
1664 return NULL;
1665 v = v->GetChildViewAt(index);
1666 }
1667 return v;
1668}
1669
1670// DropInfo --------------------------------------------------------------------
1671
1672void View::DragInfo::Reset() {
1673 possible_drag = false;
1674 start_x = start_y = 0;
1675}
1676
1677void View::DragInfo::PossibleDrag(int x, int y) {
1678 possible_drag = true;
1679 start_x = x;
1680 start_y = y;
1681}
1682
1683} // namespace
license.botbf09a502008-08-24 00:55:551684