blob: e47dbeacd88d01d11adcd67009a4b9421838eb92 [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
[email protected]2362e4f2009-05-08 00:34:055#include "views/view.h"
initial.commit09911bf2008-07-26 23:55:296
7#include <algorithm>
[email protected]1eb89e82008-08-15 12:27:038#ifndef NDEBUG
initial.commit09911bf2008-07-26 23:55:299#include <iostream>
[email protected]1eb89e82008-08-15 12:27:0310#endif
initial.commit09911bf2008-07-26 23:55:2911
[email protected]37126212009-05-06 02:23:3112#include "app/drag_drop_types.h"
[email protected]82522512009-05-15 07:37:2913#include "app/gfx/canvas.h"
[email protected]a52ca4672009-06-05 05:41:0914#include "app/gfx/path.h"
[email protected]a92b8642009-05-05 23:38:5615#include "app/l10n_util.h"
initial.commit09911bf2008-07-26 23:55:2916#include "base/logging.h"
17#include "base/message_loop.h"
[email protected]82739cf2008-09-16 00:37:5618#include "base/scoped_handle.h"
initial.commit09911bf2008-07-26 23:55:2919#include "base/string_util.h"
[email protected]d5282e72009-05-13 13:16:5220#include "third_party/skia/include/core/SkShader.h"
[email protected]2362e4f2009-05-08 00:34:0521#include "views/background.h"
22#include "views/layout_manager.h"
[email protected]3ee83f2c2009-05-10 05:58:4023#include "views/views_delegate.h"
[email protected]2362e4f2009-05-08 00:34:0524#include "views/widget/root_view.h"
[email protected]319d4ae2009-05-28 19:09:4525#include "views/widget/tooltip_manager.h"
[email protected]2362e4f2009-05-08 00:34:0526#include "views/widget/widget.h"
27#include "views/window/window.h"
[email protected]6ff244f2009-01-20 20:38:0828#if defined(OS_WIN)
[email protected]2362e4f2009-05-08 00:34:0529#include "views/accessibility/view_accessibility_wrapper.h"
[email protected]6ff244f2009-01-20 20:38:0830#endif
initial.commit09911bf2008-07-26 23:55:2931
[email protected]c2dacc92008-10-16 23:51:3832namespace views {
initial.commit09911bf2008-07-26 23:55:2933
34// static
[email protected]3ee83f2c2009-05-10 05:58:4035ViewsDelegate* ViewsDelegate::views_delegate = NULL;
36
37// static
[email protected]2362e4f2009-05-08 00:34:0538char View::kViewClassName[] = "views/View";
initial.commit09911bf2008-07-26 23:55:2939
initial.commit09911bf2008-07-26 23:55:2940/////////////////////////////////////////////////////////////////////////////
41//
42// View - constructors, destructors, initialization
43//
44/////////////////////////////////////////////////////////////////////////////
45
46View::View()
47 : id_(0),
48 group_(-1),
[email protected]6ff244f2009-01-20 20:38:0849 enabled_(true),
50 focusable_(false),
[email protected]4f3dc372009-02-24 00:10:2951 bounds_(0, 0, 0, 0),
initial.commit09911bf2008-07-26 23:55:2952 parent_(NULL),
initial.commit09911bf2008-07-26 23:55:2953 is_visible_(true),
initial.commit09911bf2008-07-26 23:55:2954 is_parent_owned_(true),
55 notify_when_visible_bounds_in_root_changes_(false),
56 registered_for_visible_bounds_notification_(false),
57 next_focusable_view_(NULL),
58 previous_focusable_view_(NULL),
[email protected]71421c3f2009-06-06 00:41:4459 registered_accelerator_count_(0),
initial.commit09911bf2008-07-26 23:55:2960 context_menu_controller_(NULL),
[email protected]6ff244f2009-01-20 20:38:0861#if defined(OS_WIN)
62 accessibility_(NULL),
63#endif
initial.commit09911bf2008-07-26 23:55:2964 drag_controller_(NULL),
65 ui_mirroring_is_enabled_for_rtl_languages_(true),
66 flip_canvas_on_paint_for_rtl_ui_(false) {
67}
68
69View::~View() {
initial.commit09911bf2008-07-26 23:55:2970 int c = static_cast<int>(child_views_.size());
71 while (--c >= 0) {
72 if (child_views_[c]->IsParentOwned())
73 delete child_views_[c];
74 else
75 child_views_[c]->SetParent(NULL);
76 }
initial.commit09911bf2008-07-26 23:55:2977}
78
79/////////////////////////////////////////////////////////////////////////////
80//
81// View - sizing
82//
83/////////////////////////////////////////////////////////////////////////////
84
[email protected]0d8ea702008-10-14 17:03:0785gfx::Rect View::GetBounds(PositionMirroringSettings settings) const {
86 gfx::Rect bounds(bounds_);
initial.commit09911bf2008-07-26 23:55:2987
88 // If the parent uses an RTL UI layout and if we are asked to transform the
89 // bounds to their mirrored position if necessary, then we should shift the
90 // rectangle appropriately.
[email protected]0d8ea702008-10-14 17:03:0791 if (settings == APPLY_MIRRORING_TRANSFORMATION)
92 bounds.set_x(MirroredX());
[email protected]4f3dc372009-02-24 00:10:2993
[email protected]0d8ea702008-10-14 17:03:0794 return bounds;
initial.commit09911bf2008-07-26 23:55:2995}
96
[email protected]6f3bb6c2008-09-17 22:25:3397// y(), width() and height() are agnostic to the RTL UI layout of the
98// parent view. x(), on the other hand, is not.
initial.commit09911bf2008-07-26 23:55:2999int View::GetX(PositionMirroringSettings settings) const {
[email protected]80f8b9f2008-10-16 18:17:47100 return settings == IGNORE_MIRRORING_TRANSFORMATION ? x() : MirroredX();
initial.commit09911bf2008-07-26 23:55:29101}
102
[email protected]80f8b9f2008-10-16 18:17:47103void View::SetBounds(const gfx::Rect& bounds) {
104 if (bounds == bounds_)
initial.commit09911bf2008-07-26 23:55:29105 return;
initial.commit09911bf2008-07-26 23:55:29106
[email protected]80f8b9f2008-10-16 18:17:47107 gfx::Rect prev = bounds_;
initial.commit09911bf2008-07-26 23:55:29108 bounds_ = bounds;
initial.commit09911bf2008-07-26 23:55:29109 DidChangeBounds(prev, bounds_);
110
111 RootView* root = GetRootView();
112 if (root) {
[email protected]80f8b9f2008-10-16 18:17:47113 bool size_changed = prev.size() != bounds_.size();
114 bool position_changed = prev.origin() != bounds_.origin();
initial.commit09911bf2008-07-26 23:55:29115 if (size_changed || position_changed)
116 root->ViewBoundsChanged(this, size_changed, position_changed);
117 }
118}
119
[email protected]80f8b9f2008-10-16 18:17:47120gfx::Rect View::GetLocalBounds(bool include_border) const {
[email protected]9a3f0ac22008-11-14 03:24:02121 if (include_border || !border_.get())
[email protected]80f8b9f2008-10-16 18:17:47122 return gfx::Rect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29123
[email protected]80f8b9f2008-10-16 18:17:47124 gfx::Insets insets;
125 border_->GetInsets(&insets);
126 return gfx::Rect(insets.left(), insets.top(),
[email protected]4a8d3272009-03-10 19:15:08127 std::max(0, width() - insets.width()),
128 std::max(0, height() - insets.height()));
initial.commit09911bf2008-07-26 23:55:29129}
130
[email protected]0a1d36b22008-10-17 19:33:09131gfx::Point View::GetPosition() const {
132 return gfx::Point(GetX(APPLY_MIRRORING_TRANSFORMATION), y());
initial.commit09911bf2008-07-26 23:55:29133}
134
[email protected]154f8bc2008-10-15 18:02:30135gfx::Size View::GetPreferredSize() {
136 if (layout_manager_.get())
137 return layout_manager_->GetPreferredSize(this);
138 return gfx::Size();
initial.commit09911bf2008-07-26 23:55:29139}
140
141void View::SizeToPreferredSize() {
[email protected]154f8bc2008-10-15 18:02:30142 gfx::Size prefsize = GetPreferredSize();
143 if ((prefsize.width() != width()) || (prefsize.height() != height()))
144 SetBounds(x(), y(), prefsize.width(), prefsize.height());
initial.commit09911bf2008-07-26 23:55:29145}
146
[email protected]7ccc52b72009-05-08 21:09:11147void View::PreferredSizeChanged() {
148 if (parent_)
149 parent_->ChildPreferredSizeChanged(this);
150}
151
[email protected]154f8bc2008-10-15 18:02:30152gfx::Size View::GetMinimumSize() {
153 return GetPreferredSize();
initial.commit09911bf2008-07-26 23:55:29154}
155
156int View::GetHeightForWidth(int w) {
157 if (layout_manager_.get())
158 return layout_manager_->GetPreferredHeightForWidth(this, w);
[email protected]154f8bc2008-10-15 18:02:30159 return GetPreferredSize().height();
initial.commit09911bf2008-07-26 23:55:29160}
161
[email protected]80f8b9f2008-10-16 18:17:47162void View::DidChangeBounds(const gfx::Rect& previous,
163 const gfx::Rect& current) {
164 Layout();
initial.commit09911bf2008-07-26 23:55:29165}
166
167void View::ScrollRectToVisible(int x, int y, int width, int height) {
168 View* parent = GetParent();
169
170 // We must take RTL UI mirroring into account when adjusting the position of
171 // the region.
172 if (parent)
173 parent->ScrollRectToVisible(
[email protected]6f3bb6c2008-09-17 22:25:33174 GetX(APPLY_MIRRORING_TRANSFORMATION) + x, View::y() + y, width, height);
initial.commit09911bf2008-07-26 23:55:29175}
176
177/////////////////////////////////////////////////////////////////////////////
178//
179// View - layout
180//
181/////////////////////////////////////////////////////////////////////////////
182
183void View::Layout() {
184 // Layout child Views
185 if (layout_manager_.get()) {
186 layout_manager_->Layout(this);
187 SchedulePaint();
[email protected]d5c4f382009-02-24 21:47:36188 // TODO(beng): We believe the right thing to do here is return since the
189 // layout manager should be handling things, but it causes
190 // regressions (missing options from Options dialog and a hang
191 // in interactive_ui_tests).
initial.commit09911bf2008-07-26 23:55:29192 }
193
194 // Lay out contents of child Views
195 int child_count = GetChildViewCount();
196 for (int i = 0; i < child_count; ++i) {
197 View* child = GetChildViewAt(i);
198 child->Layout();
199 }
200}
201
202LayoutManager* View::GetLayoutManager() const {
203 return layout_manager_.get();
204}
205
206void View::SetLayoutManager(LayoutManager* layout_manager) {
207 if (layout_manager_.get()) {
208 layout_manager_->Uninstalled(this);
209 }
210 layout_manager_.reset(layout_manager);
211 if (layout_manager_.get()) {
212 layout_manager_->Installed(this);
213 }
214}
215
[email protected]1eb89e82008-08-15 12:27:03216bool View::UILayoutIsRightToLeft() const {
217 return (ui_mirroring_is_enabled_for_rtl_languages_ &&
218 l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT);
219}
220
initial.commit09911bf2008-07-26 23:55:29221////////////////////////////////////////////////////////////////////////////////
222//
223// View - Right-to-left UI layout
224//
225////////////////////////////////////////////////////////////////////////////////
226
227inline int View::MirroredX() const {
[email protected]63329982008-10-10 21:56:57228 // TODO(beng): reimplement in terms of MirroredLeftPointForRect.
initial.commit09911bf2008-07-26 23:55:29229 View* parent = GetParent();
[email protected]80f8b9f2008-10-16 18:17:47230 if (parent && parent->UILayoutIsRightToLeft())
231 return parent->width() - x() - width();
232 return x();
initial.commit09911bf2008-07-26 23:55:29233}
234
235int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const {
236 if (!UILayoutIsRightToLeft()) {
237 return bounds.x();
238 }
[email protected]6f3bb6c2008-09-17 22:25:33239 return width() - bounds.x() - bounds.width();
initial.commit09911bf2008-07-26 23:55:29240}
241
242////////////////////////////////////////////////////////////////////////////////
243//
244// View - states
245//
246////////////////////////////////////////////////////////////////////////////////
247
248bool View::IsEnabled() const {
249 return enabled_;
250}
251
252void View::SetEnabled(bool state) {
253 if (enabled_ != state) {
254 enabled_ = state;
255 SchedulePaint();
256 }
257}
258
259bool View::IsFocusable() const {
260 return focusable_ && enabled_ && is_visible_;
261}
262
263void View::SetFocusable(bool focusable) {
264 focusable_ = focusable;
265}
266
[email protected]82166b62009-06-30 18:48:00267FocusManager* View::GetFocusManager() {
268 Widget* widget = GetWidget();
269 return widget ? widget->GetFocusManager() : NULL;
270}
271
initial.commit09911bf2008-07-26 23:55:29272bool View::HasFocus() {
initial.commit09911bf2008-07-26 23:55:29273 FocusManager* focus_manager = GetFocusManager();
274 if (focus_manager)
275 return focus_manager->GetFocusedView() == this;
276 return false;
277}
278
[email protected]5c9e97a2009-09-09 23:48:30279void View::Focus() {
280 // Set the native focus to the root view window so it receives the keyboard
281 // messages.
282 FocusManager* focus_manager = GetFocusManager();
283 if (focus_manager)
284 focus_manager->FocusNativeView(GetRootView()->GetWidget()->GetNativeView());
285}
286
initial.commit09911bf2008-07-26 23:55:29287void View::SetHotTracked(bool flag) {
288}
289
290/////////////////////////////////////////////////////////////////////////////
291//
292// View - painting
293//
294/////////////////////////////////////////////////////////////////////////////
295
[email protected]0a1d36b22008-10-17 19:33:09296void View::SchedulePaint(const gfx::Rect& r, bool urgent) {
297 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29298 return;
initial.commit09911bf2008-07-26 23:55:29299
300 if (parent_) {
301 // Translate the requested paint rect to the parent's coordinate system
302 // then pass this notification up to the parent.
[email protected]0a1d36b22008-10-17 19:33:09303 gfx::Rect paint_rect = r;
304 paint_rect.Offset(GetPosition());
initial.commit09911bf2008-07-26 23:55:29305 parent_->SchedulePaint(paint_rect, urgent);
306 }
307}
308
309void View::SchedulePaint() {
[email protected]0a1d36b22008-10-17 19:33:09310 SchedulePaint(GetLocalBounds(true), false);
initial.commit09911bf2008-07-26 23:55:29311}
312
313void View::SchedulePaint(int x, int y, int w, int h) {
[email protected]0a1d36b22008-10-17 19:33:09314 SchedulePaint(gfx::Rect(x, y, w, h), false);
initial.commit09911bf2008-07-26 23:55:29315}
316
[email protected]82522512009-05-15 07:37:29317void View::Paint(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29318 PaintBackground(canvas);
319 PaintFocusBorder(canvas);
320 PaintBorder(canvas);
321}
322
[email protected]82522512009-05-15 07:37:29323void View::PaintBackground(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02324 if (background_.get())
initial.commit09911bf2008-07-26 23:55:29325 background_->Paint(canvas, this);
326}
327
[email protected]82522512009-05-15 07:37:29328void View::PaintBorder(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02329 if (border_.get())
initial.commit09911bf2008-07-26 23:55:29330 border_->Paint(*this, canvas);
331}
332
[email protected]82522512009-05-15 07:37:29333void View::PaintFocusBorder(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29334 if (HasFocus() && IsFocusable())
[email protected]6f3bb6c2008-09-17 22:25:33335 canvas->DrawFocusRect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29336}
337
[email protected]82522512009-05-15 07:37:29338void View::PaintChildren(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29339 int i, c;
340 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
341 View* child = GetChildViewAt(i);
342 if (!child) {
343 NOTREACHED() << "Should not have a NULL child View for index in bounds";
344 continue;
345 }
346 child->ProcessPaint(canvas);
347 }
348}
349
[email protected]82522512009-05-15 07:37:29350void View::ProcessPaint(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29351 if (!IsVisible()) {
352 return;
353 }
354
355 // We're going to modify the canvas, save it's state first.
356 canvas->save();
357
358 // Paint this View and its children, setting the clip rect to the bounds
359 // of this View and translating the origin to the local bounds' top left
360 // point.
361 //
362 // Note that the X (or left) position we pass to ClipRectInt takes into
363 // consideration whether or not the view uses a right-to-left layout so that
364 // we paint our view in its mirrored position if need be.
[email protected]80f8b9f2008-10-16 18:17:47365 if (canvas->ClipRectInt(MirroredX(), y(), width(), height())) {
initial.commit09911bf2008-07-26 23:55:29366 // Non-empty clip, translate the graphics such that 0,0 corresponds to
367 // where this view is located (related to its parent).
[email protected]80f8b9f2008-10-16 18:17:47368 canvas->TranslateInt(MirroredX(), y());
initial.commit09911bf2008-07-26 23:55:29369
370 // Save the state again, so that any changes don't effect PaintChildren.
371 canvas->save();
372
373 // If the View we are about to paint requested the canvas to be flipped, we
374 // should change the transform appropriately.
375 bool flip_canvas = FlipCanvasOnPaintForRTLUI();
376 if (flip_canvas) {
[email protected]6f3bb6c2008-09-17 22:25:33377 canvas->TranslateInt(width(), 0);
initial.commit09911bf2008-07-26 23:55:29378 canvas->ScaleInt(-1, 1);
379 canvas->save();
380 }
381
382 Paint(canvas);
383
384 // We must undo the canvas mirroring once the View is done painting so that
385 // we don't pass the canvas with the mirrored transform to Views that
386 // didn't request the canvas to be flipped.
387 if (flip_canvas) {
388 canvas->restore();
389 }
390 canvas->restore();
391 PaintChildren(canvas);
392 }
393
394 // Restore the canvas's original transform.
395 canvas->restore();
396}
397
398void View::PaintNow() {
399 if (!IsVisible()) {
400 return;
401 }
402
403 View* view = GetParent();
404 if (view)
405 view->PaintNow();
406}
407
initial.commit09911bf2008-07-26 23:55:29408gfx::Insets View::GetInsets() const {
initial.commit09911bf2008-07-26 23:55:29409 gfx::Insets insets;
[email protected]9a3f0ac22008-11-14 03:24:02410 if (border_.get())
411 border_->GetInsets(&insets);
initial.commit09911bf2008-07-26 23:55:29412 return insets;
413}
414
[email protected]9abf8dd62009-06-04 06:40:42415gfx::NativeCursor View::GetCursorForPoint(Event::EventType event_type, int x,
416 int y) {
417 return NULL;
418}
419
[email protected]a52ca4672009-06-05 05:41:09420bool View::HitTest(const gfx::Point& l) const {
421 if (l.x() >= 0 && l.x() < static_cast<int>(width()) &&
422 l.y() >= 0 && l.y() < static_cast<int>(height())) {
423 if (HasHitTestMask()) {
424 gfx::Path mask;
425 GetHitTestMask(&mask);
426#if defined(OS_WIN)
427 ScopedHRGN rgn(mask.CreateHRGN());
428 return !!PtInRegion(rgn, l.x(), l.y());
429#elif defined(OS_LINUX)
430 GdkRegion* region = mask.CreateGdkRegion();
431 bool result = gdk_region_point_in(region, l.x(), l.y());
432 gdk_region_destroy(region);
433 return result;
434#endif
435 }
436 // No mask, but inside our bounds.
437 return true;
438 }
439 // Outside our bounds.
440 return false;
441}
442
initial.commit09911bf2008-07-26 23:55:29443void View::SetContextMenuController(ContextMenuController* menu_controller) {
444 context_menu_controller_ = menu_controller;
445}
446
[email protected]042811c2008-10-31 21:31:34447void View::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
448 if (!context_menu_controller_)
449 return;
450
[email protected]4f3dc372009-02-24 00:10:29451 context_menu_controller_->ShowContextMenu(this, x, y, is_mouse_gesture);
[email protected]042811c2008-10-31 21:31:34452}
453
initial.commit09911bf2008-07-26 23:55:29454/////////////////////////////////////////////////////////////////////////////
455//
456// View - tree
457//
458/////////////////////////////////////////////////////////////////////////////
459
460bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
461 const bool enabled = enabled_;
462 int drag_operations;
[email protected]613b8062008-10-14 23:45:09463 if (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location()))
[email protected]6f3bb6c2008-09-17 22:25:33464 drag_operations = GetDragOperations(e.x(), e.y());
initial.commit09911bf2008-07-26 23:55:29465 else
466 drag_operations = 0;
[email protected]6c50fc52009-03-26 19:58:51467 ContextMenuController* context_menu_controller =
468 e.IsRightMouseButton() ? context_menu_controller_ : 0;
initial.commit09911bf2008-07-26 23:55:29469
470 const bool result = OnMousePressed(e);
471 // WARNING: we may have been deleted, don't use any View variables;
472
473 if (!enabled)
474 return result;
475
476 if (drag_operations != DragDropTypes::DRAG_NONE) {
[email protected]6f3bb6c2008-09-17 22:25:33477 drag_info->PossibleDrag(e.x(), e.y());
initial.commit09911bf2008-07-26 23:55:29478 return true;
479 }
480 return !!context_menu_controller || result;
481}
482
483bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
484 // Copy the field, that way if we're deleted after drag and drop no harm is
485 // done.
486 ContextMenuController* context_menu_controller = context_menu_controller_;
487 const bool possible_drag = drag_info->possible_drag;
[email protected]6f3bb6c2008-09-17 22:25:33488 if (possible_drag && ExceededDragThreshold(drag_info->start_x - e.x(),
489 drag_info->start_y - e.y())) {
initial.commit09911bf2008-07-26 23:55:29490 DoDrag(e, drag_info->start_x, drag_info->start_y);
491 } else {
492 if (OnMouseDragged(e))
493 return true;
494 // Fall through to return value based on context menu controller.
495 }
496 // WARNING: we may have been deleted.
497 return (context_menu_controller != NULL) || possible_drag;
498}
499
500void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
501 if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
502 // Assume that if there is a context menu controller we won't be deleted
503 // from mouse released.
[email protected]96b667d2008-10-14 20:58:44504 gfx::Point location(e.location());
initial.commit09911bf2008-07-26 23:55:29505 OnMouseReleased(e, canceled);
[email protected]464fdb32009-03-19 20:25:44506 if (HitTest(location)) {
507 ConvertPointToScreen(this, &location);
508 ShowContextMenu(location.x(), location.y(), true);
509 }
initial.commit09911bf2008-07-26 23:55:29510 } else {
511 OnMouseReleased(e, canceled);
512 }
513 // WARNING: we may have been deleted.
514}
515
initial.commit09911bf2008-07-26 23:55:29516void View::AddChildView(View* v) {
[email protected]0d52b2302009-05-11 23:50:55517 AddChildView(static_cast<int>(child_views_.size()), v);
initial.commit09911bf2008-07-26 23:55:29518}
519
520void View::AddChildView(int index, View* v) {
initial.commit09911bf2008-07-26 23:55:29521 // Remove the view from its current parent if any.
522 if (v->GetParent())
523 v->GetParent()->RemoveChildView(v);
524
[email protected]0d52b2302009-05-11 23:50:55525 // Sets the prev/next focus views.
526 InitFocusSiblings(v, index);
initial.commit09911bf2008-07-26 23:55:29527
528 // Let's insert the view.
529 child_views_.insert(child_views_.begin() + index, v);
530 v->SetParent(this);
531
532 for (View* p = this; p; p = p->GetParent()) {
533 p->ViewHierarchyChangedImpl(false, true, this, v);
534 }
535 v->PropagateAddNotifications(this, v);
536 UpdateTooltip();
537 RootView* root = GetRootView();
538 if (root)
539 RegisterChildrenForVisibleBoundsNotification(root, v);
540
541 if (layout_manager_.get())
542 layout_manager_->ViewAdded(this, v);
543}
544
545View* View::GetChildViewAt(int index) const {
546 return index < GetChildViewCount() ? child_views_[index] : NULL;
547}
548
549int View::GetChildViewCount() const {
550 return static_cast<int>(child_views_.size());
551}
552
553void View::RemoveChildView(View* a_view) {
554 DoRemoveChildView(a_view, true, true, false);
555}
556
557void View::RemoveAllChildViews(bool delete_views) {
558 ViewList::iterator iter;
559 while ((iter = child_views_.begin()) != child_views_.end()) {
560 DoRemoveChildView(*iter, false, false, delete_views);
561 }
562 UpdateTooltip();
563}
564
[email protected]4768c65b2009-08-28 21:42:59565void View::DoDrag(const MouseEvent& e, int press_x, int press_y) {
566 int drag_operations = GetDragOperations(press_x, press_y);
567 if (drag_operations == DragDropTypes::DRAG_NONE)
568 return;
569
570 OSExchangeData data;
571 WriteDragData(press_x, press_y, &data);
572
573 // Message the RootView to do the drag and drop. That way if we're removed
574 // the RootView can detect it and avoid calling us back.
575 RootView* root_view = GetRootView();
576 root_view->StartDragForViewFromMouseEvent(this, data, drag_operations);
577}
578
initial.commit09911bf2008-07-26 23:55:29579void View::DoRemoveChildView(View* a_view,
580 bool update_focus_cycle,
581 bool update_tool_tip,
582 bool delete_removed_view) {
583#ifndef NDEBUG
584 DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
585 "during a paint, this will seriously " <<
586 "mess things up!";
587#endif
588 DCHECK(a_view);
589 const ViewList::iterator i = find(child_views_.begin(),
590 child_views_.end(),
591 a_view);
592 if (i != child_views_.end()) {
[email protected]0d52b2302009-05-11 23:50:55593 if (update_focus_cycle) {
initial.commit09911bf2008-07-26 23:55:29594 // Let's remove the view from the focus traversal.
595 View* next_focusable = a_view->next_focusable_view_;
596 View* prev_focusable = a_view->previous_focusable_view_;
597 if (prev_focusable)
598 prev_focusable->next_focusable_view_ = next_focusable;
599 if (next_focusable)
600 next_focusable->previous_focusable_view_ = prev_focusable;
601 }
602
603 RootView* root = GetRootView();
604 if (root)
605 UnregisterChildrenForVisibleBoundsNotification(root, a_view);
606 a_view->PropagateRemoveNotifications(this);
607 a_view->SetParent(NULL);
608
609 if (delete_removed_view && a_view->IsParentOwned())
610 delete a_view;
611
612 child_views_.erase(i);
613 }
614
615 if (update_tool_tip)
616 UpdateTooltip();
617
618 if (layout_manager_.get())
619 layout_manager_->ViewRemoved(this, a_view);
620}
621
622void View::PropagateRemoveNotifications(View* parent) {
623 int i, c;
624 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
625 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
626 }
627
628 View *t;
629 for (t = this; t; t = t->GetParent()) {
630 t->ViewHierarchyChangedImpl(true, false, parent, this);
631 }
632}
633
634void View::PropagateAddNotifications(View* parent, View* child) {
635 int i, c;
636 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
637 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
638 }
639 ViewHierarchyChangedImpl(true, true, parent, child);
640}
641
[email protected]32670b02009-03-03 00:28:00642void View::ThemeChanged() {
643 int c = GetChildViewCount();
644 for (int i = c - 1; i >= 0; --i)
645 GetChildViewAt(i)->ThemeChanged();
646}
647
initial.commit09911bf2008-07-26 23:55:29648#ifndef NDEBUG
649bool View::IsProcessingPaint() const {
650 return GetParent() && GetParent()->IsProcessingPaint();
651}
652#endif
653
[email protected]f704ee72008-11-10 21:31:59654gfx::Point View::GetKeyboardContextMenuLocation() {
655 gfx::Rect vis_bounds = GetVisibleBounds();
656 gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
657 vis_bounds.y() + vis_bounds.height() / 2);
658 ConvertPointToScreen(this, &screen_point);
659 return screen_point;
660}
661
[email protected]82739cf2008-09-16 00:37:56662bool View::HasHitTestMask() const {
663 return false;
664}
665
666void View::GetHitTestMask(gfx::Path* mask) const {
667 DCHECK(mask);
668}
669
[email protected]bb515ed2009-01-15 00:53:43670void View::ViewHierarchyChanged(bool is_add,
671 View* parent,
672 View* child) {
initial.commit09911bf2008-07-26 23:55:29673}
674
675void View::ViewHierarchyChangedImpl(bool register_accelerators,
[email protected]bb515ed2009-01-15 00:53:43676 bool is_add,
677 View* parent,
678 View* child) {
initial.commit09911bf2008-07-26 23:55:29679 if (register_accelerators) {
680 if (is_add) {
681 // If you get this registration, you are part of a subtree that has been
682 // added to the view hierarchy.
[email protected]71421c3f2009-06-06 00:41:44683 RegisterPendingAccelerators();
initial.commit09911bf2008-07-26 23:55:29684 } else {
685 if (child == this)
686 UnregisterAccelerators();
687 }
688 }
689
690 ViewHierarchyChanged(is_add, parent, child);
691}
692
693void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
694 int i, c;
695 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
696 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
697 }
698 VisibilityChanged(start, is_visible);
699}
700
701void View::VisibilityChanged(View* starting_from, bool is_visible) {
702}
703
initial.commit09911bf2008-07-26 23:55:29704void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
705 if (notify_when_visible_bounds_in_root_changes_ == value)
706 return;
707 notify_when_visible_bounds_in_root_changes_ = value;
708 RootView* root = GetRootView();
709 if (root) {
710 if (value)
711 root->RegisterViewForVisibleBoundsNotification(this);
712 else
713 root->UnregisterViewForVisibleBoundsNotification(this);
714 }
715}
716
717bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
718 return notify_when_visible_bounds_in_root_changes_;
719}
720
[email protected]0d52b2302009-05-11 23:50:55721View* View::GetViewForPoint(const gfx::Point& point) {
initial.commit09911bf2008-07-26 23:55:29722 // Walk the child Views recursively looking for the View that most
723 // tightly encloses the specified point.
724 for (int i = GetChildViewCount() - 1 ; i >= 0 ; --i) {
725 View* child = GetChildViewAt(i);
[email protected]82739cf2008-09-16 00:37:56726 if (!child->IsVisible())
initial.commit09911bf2008-07-26 23:55:29727 continue;
[email protected]82739cf2008-09-16 00:37:56728
[email protected]96b667d2008-10-14 20:58:44729 gfx::Point point_in_child_coords(point);
[email protected]82739cf2008-09-16 00:37:56730 View::ConvertPointToView(this, child, &point_in_child_coords);
[email protected]613b8062008-10-14 23:45:09731 if (child->HitTest(point_in_child_coords))
[email protected]0d52b2302009-05-11 23:50:55732 return child->GetViewForPoint(point_in_child_coords);
initial.commit09911bf2008-07-26 23:55:29733 }
734 return this;
735}
736
[email protected]a0dde122008-11-21 20:51:20737Widget* View::GetWidget() const {
738 // The root view holds a reference to this view hierarchy's Widget.
739 return parent_ ? parent_->GetWidget() : NULL;
initial.commit09911bf2008-07-26 23:55:29740}
741
[email protected]cd8c47902009-04-30 20:55:35742Window* View::GetWindow() const {
743 Widget* widget = GetWidget();
744 return widget ? widget->GetWindow() : NULL;
745}
746
initial.commit09911bf2008-07-26 23:55:29747// Get the containing RootView
748RootView* View::GetRootView() {
[email protected]a0dde122008-11-21 20:51:20749 Widget* widget = GetWidget();
750 return widget ? widget->GetRootView() : NULL;
initial.commit09911bf2008-07-26 23:55:29751}
752
753View* View::GetViewByID(int id) const {
754 if (id == id_)
755 return const_cast<View*>(this);
756
757 int view_count = GetChildViewCount();
758 for (int i = 0; i < view_count; ++i) {
759 View* child = GetChildViewAt(i);
760 View* view = child->GetViewByID(id);
761 if (view)
762 return view;
763 }
764 return NULL;
765}
766
767void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
768 if (group_ == group_id)
769 out->push_back(this);
770
771 int view_count = GetChildViewCount();
772 for (int i = 0; i < view_count; ++i)
773 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
774}
775
776View* View::GetSelectedViewForGroup(int group_id) {
777 std::vector<View*> views;
778 GetRootView()->GetViewsWithGroup(group_id, &views);
779 if (views.size() > 0)
780 return views[0];
781 else
782 return NULL;
783}
784
785void View::SetID(int id) {
786 id_ = id;
787}
788
789int View::GetID() const {
790 return id_;
791}
792
793void View::SetGroup(int gid) {
794 group_ = gid;
795}
796
797int View::GetGroup() const {
798 return group_;
799}
800
801void View::SetParent(View* parent) {
802 if (parent != parent_) {
803 parent_ = parent;
804 }
805}
806
807bool View::IsParentOf(View* v) const {
808 DCHECK(v);
809 View* parent = v->GetParent();
810 while (parent) {
811 if (this == parent)
812 return true;
813 parent = parent->GetParent();
814 }
815 return false;
816}
817
818int View::GetChildIndex(View* v) const {
819 for (int i = 0; i < GetChildViewCount(); i++) {
820 if (v == GetChildViewAt(i))
821 return i;
822 }
823 return -1;
824}
825
826///////////////////////////////////////////////////////////////////////////////
827//
828// View - focus
829//
830///////////////////////////////////////////////////////////////////////////////
831
832View* View::GetNextFocusableView() {
833 return next_focusable_view_;
834}
835
836View* View::GetPreviousFocusableView() {
837 return previous_focusable_view_;
838}
839
840void View::SetNextFocusableView(View* view) {
841 view->previous_focusable_view_ = this;
842 next_focusable_view_ = view;
843}
844
845void View::InitFocusSiblings(View* v, int index) {
846 int child_count = static_cast<int>(child_views_.size());
847
848 if (child_count == 0) {
849 v->next_focusable_view_ = NULL;
850 v->previous_focusable_view_ = NULL;
851 } else {
852 if (index == child_count) {
853 // We are inserting at the end, but the end of the child list may not be
854 // the last focusable element. Let's try to find an element with no next
855 // focusable element to link to.
856 View* last_focusable_view = NULL;
857 for (std::vector<View*>::iterator iter = child_views_.begin();
858 iter != child_views_.end(); ++iter) {
859 if (!(*iter)->next_focusable_view_) {
860 last_focusable_view = *iter;
861 break;
862 }
863 }
864 if (last_focusable_view == NULL) {
865 // Hum... there is a cycle in the focus list. Let's just insert ourself
866 // after the last child.
867 View* prev = child_views_[index - 1];
868 v->previous_focusable_view_ = prev;
869 v->next_focusable_view_ = prev->next_focusable_view_;
870 prev->next_focusable_view_->previous_focusable_view_ = v;
871 prev->next_focusable_view_ = v;
872 } else {
873 last_focusable_view->next_focusable_view_ = v;
874 v->next_focusable_view_ = NULL;
875 v->previous_focusable_view_ = last_focusable_view;
876 }
877 } else {
878 View* prev = child_views_[index]->GetPreviousFocusableView();
879 v->previous_focusable_view_ = prev;
880 v->next_focusable_view_ = child_views_[index];
881 if (prev)
882 prev->next_focusable_view_ = v;
883 child_views_[index]->previous_focusable_view_ = v;
884 }
885 }
886}
887
888#ifndef NDEBUG
889void View::PrintViewHierarchy() {
890 PrintViewHierarchyImp(0);
891}
892
893void View::PrintViewHierarchyImp(int indent) {
894 std::wostringstream buf;
895 int ind = indent;
896 while (ind-- > 0)
897 buf << L' ';
898 buf << UTF8ToWide(GetClassName());
899 buf << L' ';
900 buf << GetID();
901 buf << L' ';
[email protected]80f8b9f2008-10-16 18:17:47902 buf << bounds_.x() << L"," << bounds_.y() << L",";
903 buf << bounds_.right() << L"," << bounds_.bottom();
initial.commit09911bf2008-07-26 23:55:29904 buf << L' ';
905 buf << this;
906
907 LOG(INFO) << buf.str();
908 std::cout << buf.str() << std::endl;
909
910 for (int i = 0; i < GetChildViewCount(); ++i) {
911 GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
912 }
913}
914
915
916void View::PrintFocusHierarchy() {
917 PrintFocusHierarchyImp(0);
918}
919
920void View::PrintFocusHierarchyImp(int indent) {
921 std::wostringstream buf;
922 int ind = indent;
923 while (ind-- > 0)
924 buf << L' ';
925 buf << UTF8ToWide(GetClassName());
926 buf << L' ';
927 buf << GetID();
928 buf << L' ';
929 buf << GetClassName().c_str();
930 buf << L' ';
931 buf << this;
932
933 LOG(INFO) << buf.str();
934 std::cout << buf.str() << std::endl;
935
936 if (GetChildViewCount() > 0)
937 GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
938
939 View* v = GetNextFocusableView();
940 if (v)
941 v->PrintFocusHierarchyImp(indent);
942}
943#endif
944
945////////////////////////////////////////////////////////////////////////////////
946//
947// View - accelerators
948//
949////////////////////////////////////////////////////////////////////////////////
950
951void View::AddAccelerator(const Accelerator& accelerator) {
952 if (!accelerators_.get())
953 accelerators_.reset(new std::vector<Accelerator>());
[email protected]71421c3f2009-06-06 00:41:44954
955 std::vector<Accelerator>::iterator iter =
956 std::find(accelerators_->begin(), accelerators_->end(), accelerator);
957 DCHECK(iter == accelerators_->end())
958 << "Registering the same accelerator multiple times";
959
initial.commit09911bf2008-07-26 23:55:29960 accelerators_->push_back(accelerator);
[email protected]71421c3f2009-06-06 00:41:44961 RegisterPendingAccelerators();
initial.commit09911bf2008-07-26 23:55:29962}
963
[email protected]e8e0f362008-11-08 01:13:25964void View::RemoveAccelerator(const Accelerator& accelerator) {
965 std::vector<Accelerator>::iterator iter;
966 if (!accelerators_.get() ||
967 ((iter = std::find(accelerators_->begin(), accelerators_->end(),
968 accelerator)) == accelerators_->end())) {
969 NOTREACHED() << "Removing non-existing accelerator";
970 return;
971 }
972
[email protected]4bd23f32009-06-08 20:59:19973 size_t index = iter - accelerators_->begin();
[email protected]e8e0f362008-11-08 01:13:25974 accelerators_->erase(iter);
[email protected]71421c3f2009-06-06 00:41:44975 if (index >= registered_accelerator_count_) {
976 // The accelerator is not registered to FocusManager.
977 return;
978 }
979 --registered_accelerator_count_;
980
[email protected]e8e0f362008-11-08 01:13:25981 RootView* root_view = GetRootView();
982 if (!root_view) {
983 // We are not part of a view hierarchy, so there is nothing to do as we
984 // removed ourselves from accelerators_, we won't be registered when added
985 // to one.
986 return;
987 }
988
[email protected]f3735c5d2009-03-19 17:26:23989 // TODO(port): Fix this once we have a FocusManger for Linux.
990#if defined(OS_WIN)
[email protected]e8e0f362008-11-08 01:13:25991 FocusManager* focus_manager = GetFocusManager();
992 if (focus_manager) {
993 // We may not have a FocusManager if the window containing us is being
994 // closed, in which case the FocusManager is being deleted so there is
995 // nothing to unregister.
996 focus_manager->UnregisterAccelerator(accelerator, this);
997 }
[email protected]f3735c5d2009-03-19 17:26:23998#endif
[email protected]e8e0f362008-11-08 01:13:25999}
1000
initial.commit09911bf2008-07-26 23:55:291001void View::ResetAccelerators() {
[email protected]71421c3f2009-06-06 00:41:441002 if (accelerators_.get())
initial.commit09911bf2008-07-26 23:55:291003 UnregisterAccelerators();
initial.commit09911bf2008-07-26 23:55:291004}
1005
[email protected]71421c3f2009-06-06 00:41:441006void View::RegisterPendingAccelerators() {
1007 if (!accelerators_.get() ||
1008 registered_accelerator_count_ == accelerators_->size()) {
1009 // No accelerators are waiting for registration.
initial.commit09911bf2008-07-26 23:55:291010 return;
[email protected]71421c3f2009-06-06 00:41:441011 }
initial.commit09911bf2008-07-26 23:55:291012
1013 RootView* root_view = GetRootView();
1014 if (!root_view) {
1015 // We are not yet part of a view hierarchy, we'll register ourselves once
1016 // added to one.
1017 return;
1018 }
[email protected]f3735c5d2009-03-19 17:26:231019
initial.commit09911bf2008-07-26 23:55:291020 FocusManager* focus_manager = GetFocusManager();
1021 if (!focus_manager) {
1022 // Some crash reports seem to show that we may get cases where we have no
1023 // focus manager (see bug #1291225). This should never be the case, just
1024 // making sure we don't crash.
1025 NOTREACHED();
1026 return;
1027 }
[email protected]71421c3f2009-06-06 00:41:441028 std::vector<Accelerator>::const_iterator iter;
1029 for (iter = accelerators_->begin() + registered_accelerator_count_;
initial.commit09911bf2008-07-26 23:55:291030 iter != accelerators_->end(); ++iter) {
1031 focus_manager->RegisterAccelerator(*iter, this);
1032 }
[email protected]71421c3f2009-06-06 00:41:441033 registered_accelerator_count_ = accelerators_->size();
initial.commit09911bf2008-07-26 23:55:291034}
1035
1036void View::UnregisterAccelerators() {
1037 if (!accelerators_.get())
1038 return;
1039
1040 RootView* root_view = GetRootView();
1041 if (root_view) {
[email protected]f3735c5d2009-03-19 17:26:231042 // TODO(port): Fix this once we have a FocusManger for Linux.
1043#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:291044 FocusManager* focus_manager = GetFocusManager();
1045 if (focus_manager) {
1046 // We may not have a FocusManager if the window containing us is being
1047 // closed, in which case the FocusManager is being deleted so there is
1048 // nothing to unregister.
1049 focus_manager->UnregisterAccelerators(this);
1050 }
[email protected]71421c3f2009-06-06 00:41:441051 accelerators_->clear();
1052 accelerators_.reset();
1053 registered_accelerator_count_ = 0;
[email protected]f3735c5d2009-03-19 17:26:231054#endif
initial.commit09911bf2008-07-26 23:55:291055 }
1056}
1057
initial.commit09911bf2008-07-26 23:55:291058int View::GetDragOperations(int press_x, int press_y) {
1059 if (!drag_controller_)
1060 return DragDropTypes::DRAG_NONE;
1061 return drag_controller_->GetDragOperations(this, press_x, press_y);
1062}
1063
1064void View::WriteDragData(int press_x, int press_y, OSExchangeData* data) {
1065 DCHECK(drag_controller_);
1066 drag_controller_->WriteDragData(this, press_x, press_y, data);
1067}
1068
1069void View::OnDragDone() {
1070}
1071
1072bool View::InDrag() {
1073 RootView* root_view = GetRootView();
1074 return root_view ? (root_view->GetDragView() == this) : false;
1075}
1076
initial.commit09911bf2008-07-26 23:55:291077// static
[email protected]bb515ed2009-01-15 00:53:431078void View::ConvertPointToView(const View* src,
1079 const View* dst,
1080 gfx::Point* point) {
initial.commit09911bf2008-07-26 23:55:291081 ConvertPointToView(src, dst, point, true);
1082}
1083
1084// static
[email protected]bb515ed2009-01-15 00:53:431085void View::ConvertPointToView(const View* src,
1086 const View* dst,
1087 gfx::Point* point,
initial.commit09911bf2008-07-26 23:55:291088 bool try_other_direction) {
1089 // src can be NULL
1090 DCHECK(dst);
1091 DCHECK(point);
1092
[email protected]bb515ed2009-01-15 00:53:431093 const View* v;
initial.commit09911bf2008-07-26 23:55:291094 gfx::Point offset;
1095
1096 for (v = dst; v && v != src; v = v->GetParent()) {
1097 offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
[email protected]6f3bb6c2008-09-17 22:25:331098 offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291099 }
1100
1101 // The source was not found. The caller wants a conversion
1102 // from a view to a transitive parent.
1103 if (src && v == NULL && try_other_direction) {
1104 gfx::Point p;
1105 // note: try_other_direction is force to FALSE so we don't
1106 // end up in an infinite recursion should both src and dst
1107 // are not parented.
1108 ConvertPointToView(dst, src, &p, false);
1109 // since the src and dst are inverted, p should also be negated
1110 point->SetPoint(point->x() - p.x(), point->y() - p.y());
1111 } else {
1112 point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
1113
1114 // If src is NULL, sp is in the screen coordinate system
1115 if (src == NULL) {
[email protected]a0dde122008-11-21 20:51:201116 Widget* widget = dst->GetWidget();
1117 if (widget) {
[email protected]3b680a82008-12-17 02:03:231118 gfx::Rect b;
[email protected]a0dde122008-11-21 20:51:201119 widget->GetBounds(&b, false);
[email protected]3b680a82008-12-17 02:03:231120 point->SetPoint(point->x() - b.x(), point->y() - b.y());
initial.commit09911bf2008-07-26 23:55:291121 }
1122 }
1123 }
1124}
1125
1126// static
[email protected]2fb6d462009-02-13 18:40:101127void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291128 DCHECK(src);
1129 DCHECK(p);
[email protected]96b667d2008-10-14 20:58:441130
[email protected]96b667d2008-10-14 20:58:441131 gfx::Point offset;
[email protected]2fb6d462009-02-13 18:40:101132 for (const View* v = src; v; v = v->GetParent()) {
[email protected]96b667d2008-10-14 20:58:441133 offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION));
1134 offset.set_y(offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291135 }
[email protected]96b667d2008-10-14 20:58:441136 p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
initial.commit09911bf2008-07-26 23:55:291137}
1138
1139// static
[email protected]2fb6d462009-02-13 18:40:101140void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
[email protected]96b667d2008-10-14 20:58:441141 gfx::Point t;
[email protected]2fb6d462009-02-13 18:40:101142 ConvertPointToWidget(dest, &t);
[email protected]96b667d2008-10-14 20:58:441143 p->SetPoint(p->x() - t.x(), p->y() - t.y());
initial.commit09911bf2008-07-26 23:55:291144}
1145
1146// static
[email protected]2fb6d462009-02-13 18:40:101147void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291148 DCHECK(src);
1149 DCHECK(p);
1150
[email protected]96b667d2008-10-14 20:58:441151 // If the view is not connected to a tree, there's nothing we can do.
[email protected]a0dde122008-11-21 20:51:201152 Widget* widget = src->GetWidget();
1153 if (widget) {
1154 ConvertPointToWidget(src, p);
[email protected]3b680a82008-12-17 02:03:231155 gfx::Rect r;
[email protected]a0dde122008-11-21 20:51:201156 widget->GetBounds(&r, false);
[email protected]3b680a82008-12-17 02:03:231157 p->SetPoint(p->x() + r.x(), p->y() + r.y());
initial.commit09911bf2008-07-26 23:55:291158 }
1159}
1160
1161/////////////////////////////////////////////////////////////////////////////
1162//
1163// View - event handlers
1164//
1165/////////////////////////////////////////////////////////////////////////////
1166
1167bool View::OnMousePressed(const MouseEvent& e) {
1168 return false;
1169}
1170
1171bool View::OnMouseDragged(const MouseEvent& e) {
1172 return false;
1173}
1174
1175void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
1176}
1177
1178void View::OnMouseMoved(const MouseEvent& e) {
1179}
1180
1181void View::OnMouseEntered(const MouseEvent& e) {
1182}
1183
1184void View::OnMouseExited(const MouseEvent& e) {
1185}
1186
1187void View::SetMouseHandler(View *new_mouse_handler) {
1188 // It is valid for new_mouse_handler to be NULL
1189 if (parent_) {
1190 parent_->SetMouseHandler(new_mouse_handler);
1191 }
1192}
1193
1194void View::SetVisible(bool flag) {
1195 if (flag != is_visible_) {
1196 // If the tab is currently visible, schedule paint to
1197 // refresh parent
1198 if (IsVisible()) {
1199 SchedulePaint();
1200 }
1201
1202 is_visible_ = flag;
1203
1204 // This notifies all subviews recursively.
1205 PropagateVisibilityNotifications(this, flag);
1206
1207 // If we are newly visible, schedule paint.
1208 if (IsVisible()) {
1209 SchedulePaint();
1210 }
1211 }
1212}
1213
1214bool View::IsVisibleInRootView() const {
1215 View* parent = GetParent();
1216 if (IsVisible() && parent)
1217 return parent->IsVisibleInRootView();
1218 else
1219 return false;
1220}
1221
initial.commit09911bf2008-07-26 23:55:291222/////////////////////////////////////////////////////////////////////////////
1223//
1224// View - keyboard and focus
1225//
1226/////////////////////////////////////////////////////////////////////////////
1227
1228void View::RequestFocus() {
1229 RootView* rv = GetRootView();
[email protected]830e2062009-02-13 18:27:381230 if (rv && IsFocusable())
initial.commit09911bf2008-07-26 23:55:291231 rv->FocusView(this);
initial.commit09911bf2008-07-26 23:55:291232}
1233
1234void View::WillGainFocus() {
1235}
1236
1237void View::DidGainFocus() {
1238}
1239
1240void View::WillLoseFocus() {
1241}
1242
1243bool View::OnKeyPressed(const KeyEvent& e) {
1244 return false;
1245}
1246
1247bool View::OnKeyReleased(const KeyEvent& e) {
1248 return false;
1249}
1250
1251bool View::OnMouseWheel(const MouseWheelEvent& e) {
1252 return false;
1253}
1254
1255void View::SetDragController(DragController* drag_controller) {
1256 drag_controller_ = drag_controller;
1257}
1258
1259DragController* View::GetDragController() {
1260 return drag_controller_;
1261}
1262
[email protected]134c47b92009-08-19 03:33:441263bool View::GetDropFormats(
1264 int* formats,
1265 std::set<OSExchangeData::CustomFormat>* custom_formats) {
1266 return false;
1267}
1268
1269bool View::AreDropTypesRequired() {
1270 return false;
1271}
1272
initial.commit09911bf2008-07-26 23:55:291273bool View::CanDrop(const OSExchangeData& data) {
[email protected]134c47b92009-08-19 03:33:441274 // TODO(sky): when I finish up migration, this should default to true.
initial.commit09911bf2008-07-26 23:55:291275 return false;
1276}
1277
1278void View::OnDragEntered(const DropTargetEvent& event) {
1279}
1280
1281int View::OnDragUpdated(const DropTargetEvent& event) {
1282 return DragDropTypes::DRAG_NONE;
1283}
1284
1285void View::OnDragExited() {
1286}
1287
1288int View::OnPerformDrop(const DropTargetEvent& event) {
1289 return DragDropTypes::DRAG_NONE;
1290}
1291
initial.commit09911bf2008-07-26 23:55:291292// static
1293bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1294 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1295 abs(delta_y) > GetVerticalDragThreshold());
1296}
1297
initial.commit09911bf2008-07-26 23:55:291298// Tooltips -----------------------------------------------------------------
1299bool View::GetTooltipText(int x, int y, std::wstring* tooltip) {
1300 return false;
1301}
1302
[email protected]0a1d36b22008-10-17 19:33:091303bool View::GetTooltipTextOrigin(int x, int y, gfx::Point* loc) {
initial.commit09911bf2008-07-26 23:55:291304 return false;
1305}
1306
1307void View::TooltipTextChanged() {
[email protected]a0dde122008-11-21 20:51:201308 Widget* widget = GetWidget();
1309 if (widget && widget->GetTooltipManager())
1310 widget->GetTooltipManager()->TooltipTextChanged(this);
initial.commit09911bf2008-07-26 23:55:291311}
1312
1313void View::UpdateTooltip() {
[email protected]a0dde122008-11-21 20:51:201314 Widget* widget = GetWidget();
1315 if (widget && widget->GetTooltipManager())
1316 widget->GetTooltipManager()->UpdateTooltip();
initial.commit09911bf2008-07-26 23:55:291317}
1318
1319void View::SetParentOwned(bool f) {
1320 is_parent_owned_ = f;
1321}
1322
1323bool View::IsParentOwned() const {
1324 return is_parent_owned_;
1325}
1326
1327std::string View::GetClassName() const {
1328 return kViewClassName;
1329}
1330
[email protected]5c2b98b2009-03-09 20:55:541331View* View::GetAncestorWithClassName(const std::string& name) {
1332 for (View* view = this; view; view = view->GetParent()) {
1333 if (view->GetClassName() == name)
1334 return view;
1335 }
1336 return NULL;
1337}
1338
initial.commit09911bf2008-07-26 23:55:291339gfx::Rect View::GetVisibleBounds() {
[email protected]b6296fd2009-02-13 17:34:161340 if (!IsVisibleInRootView())
1341 return gfx::Rect();
[email protected]6f3bb6c2008-09-17 22:25:331342 gfx::Rect vis_bounds(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:291343 gfx::Rect ancestor_bounds;
1344 View* view = this;
1345 int root_x = 0;
1346 int root_y = 0;
initial.commit09911bf2008-07-26 23:55:291347 while (view != NULL && !vis_bounds.IsEmpty()) {
1348 root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
[email protected]6f3bb6c2008-09-17 22:25:331349 root_y += view->y();
1350 vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y());
initial.commit09911bf2008-07-26 23:55:291351 View* ancestor = view->GetParent();
1352 if (ancestor != NULL) {
[email protected]6f3bb6c2008-09-17 22:25:331353 ancestor_bounds.SetRect(0, 0, ancestor->width(),
1354 ancestor->height());
initial.commit09911bf2008-07-26 23:55:291355 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
[email protected]a0dde122008-11-21 20:51:201356 } else if (!view->GetWidget()) {
1357 // If the view has no Widget, we're not visible. Return an empty rect.
initial.commit09911bf2008-07-26 23:55:291358 return gfx::Rect();
1359 }
1360 view = ancestor;
1361 }
1362 if (vis_bounds.IsEmpty())
1363 return vis_bounds;
1364 // Convert back to this views coordinate system.
1365 vis_bounds.Offset(-root_x, -root_y);
1366 return vis_bounds;
1367}
1368
1369int View::GetPageScrollIncrement(ScrollView* scroll_view,
1370 bool is_horizontal, bool is_positive) {
1371 return 0;
1372}
1373
1374int View::GetLineScrollIncrement(ScrollView* scroll_view,
1375 bool is_horizontal, bool is_positive) {
1376 return 0;
1377}
1378
[email protected]4a190632009-05-09 01:07:421379ThemeProvider* View::GetThemeProvider() {
1380 Widget* widget = GetWidget();
1381 return widget ? widget->GetThemeProvider() : NULL;
1382}
1383
initial.commit09911bf2008-07-26 23:55:291384// static
1385void View::RegisterChildrenForVisibleBoundsNotification(
1386 RootView* root, View* view) {
1387 DCHECK(root && view);
1388 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1389 root->RegisterViewForVisibleBoundsNotification(view);
1390 for (int i = 0; i < view->GetChildViewCount(); ++i)
1391 RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i));
1392}
1393
1394// static
1395void View::UnregisterChildrenForVisibleBoundsNotification(
1396 RootView* root, View* view) {
1397 DCHECK(root && view);
1398 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1399 root->UnregisterViewForVisibleBoundsNotification(view);
1400 for (int i = 0; i < view->GetChildViewCount(); ++i)
1401 UnregisterChildrenForVisibleBoundsNotification(root,
1402 view->GetChildViewAt(i));
1403}
1404
1405void View::AddDescendantToNotify(View* view) {
1406 DCHECK(view);
1407 if (!descendants_to_notify_.get())
1408 descendants_to_notify_.reset(new ViewList());
1409 descendants_to_notify_->push_back(view);
1410}
1411
1412void View::RemoveDescendantToNotify(View* view) {
1413 DCHECK(view && descendants_to_notify_.get());
1414 ViewList::iterator i = find(descendants_to_notify_->begin(),
1415 descendants_to_notify_->end(),
1416 view);
1417 DCHECK(i != descendants_to_notify_->end());
1418 descendants_to_notify_->erase(i);
1419 if (descendants_to_notify_->empty())
1420 descendants_to_notify_.reset();
1421}
1422
initial.commit09911bf2008-07-26 23:55:291423// DropInfo --------------------------------------------------------------------
1424
1425void View::DragInfo::Reset() {
1426 possible_drag = false;
1427 start_x = start_y = 0;
1428}
1429
1430void View::DragInfo::PossibleDrag(int x, int y) {
1431 possible_drag = true;
1432 start_x = x;
1433 start_y = y;
1434}
1435
1436} // namespace