blob: 30a6e74d3907204429758d50b78765a1be57d615 [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
279void View::SetHotTracked(bool flag) {
280}
281
282/////////////////////////////////////////////////////////////////////////////
283//
284// View - painting
285//
286/////////////////////////////////////////////////////////////////////////////
287
[email protected]0a1d36b22008-10-17 19:33:09288void View::SchedulePaint(const gfx::Rect& r, bool urgent) {
289 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29290 return;
initial.commit09911bf2008-07-26 23:55:29291
292 if (parent_) {
293 // Translate the requested paint rect to the parent's coordinate system
294 // then pass this notification up to the parent.
[email protected]0a1d36b22008-10-17 19:33:09295 gfx::Rect paint_rect = r;
296 paint_rect.Offset(GetPosition());
initial.commit09911bf2008-07-26 23:55:29297 parent_->SchedulePaint(paint_rect, urgent);
298 }
299}
300
301void View::SchedulePaint() {
[email protected]0a1d36b22008-10-17 19:33:09302 SchedulePaint(GetLocalBounds(true), false);
initial.commit09911bf2008-07-26 23:55:29303}
304
305void View::SchedulePaint(int x, int y, int w, int h) {
[email protected]0a1d36b22008-10-17 19:33:09306 SchedulePaint(gfx::Rect(x, y, w, h), false);
initial.commit09911bf2008-07-26 23:55:29307}
308
[email protected]82522512009-05-15 07:37:29309void View::Paint(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29310 PaintBackground(canvas);
311 PaintFocusBorder(canvas);
312 PaintBorder(canvas);
313}
314
[email protected]82522512009-05-15 07:37:29315void View::PaintBackground(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02316 if (background_.get())
initial.commit09911bf2008-07-26 23:55:29317 background_->Paint(canvas, this);
318}
319
[email protected]82522512009-05-15 07:37:29320void View::PaintBorder(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02321 if (border_.get())
initial.commit09911bf2008-07-26 23:55:29322 border_->Paint(*this, canvas);
323}
324
[email protected]82522512009-05-15 07:37:29325void View::PaintFocusBorder(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29326 if (HasFocus() && IsFocusable())
[email protected]6f3bb6c2008-09-17 22:25:33327 canvas->DrawFocusRect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29328}
329
[email protected]82522512009-05-15 07:37:29330void View::PaintChildren(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29331 int i, c;
332 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
333 View* child = GetChildViewAt(i);
334 if (!child) {
335 NOTREACHED() << "Should not have a NULL child View for index in bounds";
336 continue;
337 }
338 child->ProcessPaint(canvas);
339 }
340}
341
[email protected]82522512009-05-15 07:37:29342void View::ProcessPaint(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29343 if (!IsVisible()) {
344 return;
345 }
346
347 // We're going to modify the canvas, save it's state first.
348 canvas->save();
349
350 // Paint this View and its children, setting the clip rect to the bounds
351 // of this View and translating the origin to the local bounds' top left
352 // point.
353 //
354 // Note that the X (or left) position we pass to ClipRectInt takes into
355 // consideration whether or not the view uses a right-to-left layout so that
356 // we paint our view in its mirrored position if need be.
[email protected]80f8b9f2008-10-16 18:17:47357 if (canvas->ClipRectInt(MirroredX(), y(), width(), height())) {
initial.commit09911bf2008-07-26 23:55:29358 // Non-empty clip, translate the graphics such that 0,0 corresponds to
359 // where this view is located (related to its parent).
[email protected]80f8b9f2008-10-16 18:17:47360 canvas->TranslateInt(MirroredX(), y());
initial.commit09911bf2008-07-26 23:55:29361
362 // Save the state again, so that any changes don't effect PaintChildren.
363 canvas->save();
364
365 // If the View we are about to paint requested the canvas to be flipped, we
366 // should change the transform appropriately.
367 bool flip_canvas = FlipCanvasOnPaintForRTLUI();
368 if (flip_canvas) {
[email protected]6f3bb6c2008-09-17 22:25:33369 canvas->TranslateInt(width(), 0);
initial.commit09911bf2008-07-26 23:55:29370 canvas->ScaleInt(-1, 1);
371 canvas->save();
372 }
373
374 Paint(canvas);
375
376 // We must undo the canvas mirroring once the View is done painting so that
377 // we don't pass the canvas with the mirrored transform to Views that
378 // didn't request the canvas to be flipped.
379 if (flip_canvas) {
380 canvas->restore();
381 }
382 canvas->restore();
383 PaintChildren(canvas);
384 }
385
386 // Restore the canvas's original transform.
387 canvas->restore();
388}
389
390void View::PaintNow() {
391 if (!IsVisible()) {
392 return;
393 }
394
395 View* view = GetParent();
396 if (view)
397 view->PaintNow();
398}
399
initial.commit09911bf2008-07-26 23:55:29400gfx::Insets View::GetInsets() const {
initial.commit09911bf2008-07-26 23:55:29401 gfx::Insets insets;
[email protected]9a3f0ac22008-11-14 03:24:02402 if (border_.get())
403 border_->GetInsets(&insets);
initial.commit09911bf2008-07-26 23:55:29404 return insets;
405}
406
[email protected]9abf8dd62009-06-04 06:40:42407gfx::NativeCursor View::GetCursorForPoint(Event::EventType event_type, int x,
408 int y) {
409 return NULL;
410}
411
[email protected]a52ca4672009-06-05 05:41:09412bool View::HitTest(const gfx::Point& l) const {
413 if (l.x() >= 0 && l.x() < static_cast<int>(width()) &&
414 l.y() >= 0 && l.y() < static_cast<int>(height())) {
415 if (HasHitTestMask()) {
416 gfx::Path mask;
417 GetHitTestMask(&mask);
418#if defined(OS_WIN)
419 ScopedHRGN rgn(mask.CreateHRGN());
420 return !!PtInRegion(rgn, l.x(), l.y());
421#elif defined(OS_LINUX)
422 GdkRegion* region = mask.CreateGdkRegion();
423 bool result = gdk_region_point_in(region, l.x(), l.y());
424 gdk_region_destroy(region);
425 return result;
426#endif
427 }
428 // No mask, but inside our bounds.
429 return true;
430 }
431 // Outside our bounds.
432 return false;
433}
434
initial.commit09911bf2008-07-26 23:55:29435void View::SetContextMenuController(ContextMenuController* menu_controller) {
436 context_menu_controller_ = menu_controller;
437}
438
[email protected]042811c2008-10-31 21:31:34439void View::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
440 if (!context_menu_controller_)
441 return;
442
[email protected]4f3dc372009-02-24 00:10:29443 context_menu_controller_->ShowContextMenu(this, x, y, is_mouse_gesture);
[email protected]042811c2008-10-31 21:31:34444}
445
initial.commit09911bf2008-07-26 23:55:29446/////////////////////////////////////////////////////////////////////////////
447//
448// View - tree
449//
450/////////////////////////////////////////////////////////////////////////////
451
452bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
453 const bool enabled = enabled_;
454 int drag_operations;
[email protected]613b8062008-10-14 23:45:09455 if (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location()))
[email protected]6f3bb6c2008-09-17 22:25:33456 drag_operations = GetDragOperations(e.x(), e.y());
initial.commit09911bf2008-07-26 23:55:29457 else
458 drag_operations = 0;
[email protected]6c50fc52009-03-26 19:58:51459 ContextMenuController* context_menu_controller =
460 e.IsRightMouseButton() ? context_menu_controller_ : 0;
initial.commit09911bf2008-07-26 23:55:29461
462 const bool result = OnMousePressed(e);
463 // WARNING: we may have been deleted, don't use any View variables;
464
465 if (!enabled)
466 return result;
467
468 if (drag_operations != DragDropTypes::DRAG_NONE) {
[email protected]6f3bb6c2008-09-17 22:25:33469 drag_info->PossibleDrag(e.x(), e.y());
initial.commit09911bf2008-07-26 23:55:29470 return true;
471 }
472 return !!context_menu_controller || result;
473}
474
475bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
476 // Copy the field, that way if we're deleted after drag and drop no harm is
477 // done.
478 ContextMenuController* context_menu_controller = context_menu_controller_;
479 const bool possible_drag = drag_info->possible_drag;
[email protected]6f3bb6c2008-09-17 22:25:33480 if (possible_drag && ExceededDragThreshold(drag_info->start_x - e.x(),
481 drag_info->start_y - e.y())) {
initial.commit09911bf2008-07-26 23:55:29482 DoDrag(e, drag_info->start_x, drag_info->start_y);
483 } else {
484 if (OnMouseDragged(e))
485 return true;
486 // Fall through to return value based on context menu controller.
487 }
488 // WARNING: we may have been deleted.
489 return (context_menu_controller != NULL) || possible_drag;
490}
491
492void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
493 if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
494 // Assume that if there is a context menu controller we won't be deleted
495 // from mouse released.
[email protected]96b667d2008-10-14 20:58:44496 gfx::Point location(e.location());
initial.commit09911bf2008-07-26 23:55:29497 OnMouseReleased(e, canceled);
[email protected]464fdb32009-03-19 20:25:44498 if (HitTest(location)) {
499 ConvertPointToScreen(this, &location);
500 ShowContextMenu(location.x(), location.y(), true);
501 }
initial.commit09911bf2008-07-26 23:55:29502 } else {
503 OnMouseReleased(e, canceled);
504 }
505 // WARNING: we may have been deleted.
506}
507
initial.commit09911bf2008-07-26 23:55:29508void View::AddChildView(View* v) {
[email protected]0d52b2302009-05-11 23:50:55509 AddChildView(static_cast<int>(child_views_.size()), v);
initial.commit09911bf2008-07-26 23:55:29510}
511
512void View::AddChildView(int index, View* v) {
initial.commit09911bf2008-07-26 23:55:29513 // Remove the view from its current parent if any.
514 if (v->GetParent())
515 v->GetParent()->RemoveChildView(v);
516
[email protected]0d52b2302009-05-11 23:50:55517 // Sets the prev/next focus views.
518 InitFocusSiblings(v, index);
initial.commit09911bf2008-07-26 23:55:29519
520 // Let's insert the view.
521 child_views_.insert(child_views_.begin() + index, v);
522 v->SetParent(this);
523
524 for (View* p = this; p; p = p->GetParent()) {
525 p->ViewHierarchyChangedImpl(false, true, this, v);
526 }
527 v->PropagateAddNotifications(this, v);
528 UpdateTooltip();
529 RootView* root = GetRootView();
530 if (root)
531 RegisterChildrenForVisibleBoundsNotification(root, v);
532
533 if (layout_manager_.get())
534 layout_manager_->ViewAdded(this, v);
535}
536
537View* View::GetChildViewAt(int index) const {
538 return index < GetChildViewCount() ? child_views_[index] : NULL;
539}
540
541int View::GetChildViewCount() const {
542 return static_cast<int>(child_views_.size());
543}
544
545void View::RemoveChildView(View* a_view) {
546 DoRemoveChildView(a_view, true, true, false);
547}
548
549void View::RemoveAllChildViews(bool delete_views) {
550 ViewList::iterator iter;
551 while ((iter = child_views_.begin()) != child_views_.end()) {
552 DoRemoveChildView(*iter, false, false, delete_views);
553 }
554 UpdateTooltip();
555}
556
557void View::DoRemoveChildView(View* a_view,
558 bool update_focus_cycle,
559 bool update_tool_tip,
560 bool delete_removed_view) {
561#ifndef NDEBUG
562 DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
563 "during a paint, this will seriously " <<
564 "mess things up!";
565#endif
566 DCHECK(a_view);
567 const ViewList::iterator i = find(child_views_.begin(),
568 child_views_.end(),
569 a_view);
570 if (i != child_views_.end()) {
[email protected]0d52b2302009-05-11 23:50:55571 if (update_focus_cycle) {
initial.commit09911bf2008-07-26 23:55:29572 // Let's remove the view from the focus traversal.
573 View* next_focusable = a_view->next_focusable_view_;
574 View* prev_focusable = a_view->previous_focusable_view_;
575 if (prev_focusable)
576 prev_focusable->next_focusable_view_ = next_focusable;
577 if (next_focusable)
578 next_focusable->previous_focusable_view_ = prev_focusable;
579 }
580
581 RootView* root = GetRootView();
582 if (root)
583 UnregisterChildrenForVisibleBoundsNotification(root, a_view);
584 a_view->PropagateRemoveNotifications(this);
585 a_view->SetParent(NULL);
586
587 if (delete_removed_view && a_view->IsParentOwned())
588 delete a_view;
589
590 child_views_.erase(i);
591 }
592
593 if (update_tool_tip)
594 UpdateTooltip();
595
596 if (layout_manager_.get())
597 layout_manager_->ViewRemoved(this, a_view);
598}
599
600void View::PropagateRemoveNotifications(View* parent) {
601 int i, c;
602 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
603 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
604 }
605
606 View *t;
607 for (t = this; t; t = t->GetParent()) {
608 t->ViewHierarchyChangedImpl(true, false, parent, this);
609 }
610}
611
612void View::PropagateAddNotifications(View* parent, View* child) {
613 int i, c;
614 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
615 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
616 }
617 ViewHierarchyChangedImpl(true, true, parent, child);
618}
619
[email protected]32670b02009-03-03 00:28:00620void View::ThemeChanged() {
621 int c = GetChildViewCount();
622 for (int i = c - 1; i >= 0; --i)
623 GetChildViewAt(i)->ThemeChanged();
624}
625
initial.commit09911bf2008-07-26 23:55:29626#ifndef NDEBUG
627bool View::IsProcessingPaint() const {
628 return GetParent() && GetParent()->IsProcessingPaint();
629}
630#endif
631
[email protected]f704ee72008-11-10 21:31:59632gfx::Point View::GetKeyboardContextMenuLocation() {
633 gfx::Rect vis_bounds = GetVisibleBounds();
634 gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
635 vis_bounds.y() + vis_bounds.height() / 2);
636 ConvertPointToScreen(this, &screen_point);
637 return screen_point;
638}
639
[email protected]82739cf2008-09-16 00:37:56640bool View::HasHitTestMask() const {
641 return false;
642}
643
644void View::GetHitTestMask(gfx::Path* mask) const {
645 DCHECK(mask);
646}
647
[email protected]bb515ed2009-01-15 00:53:43648void View::ViewHierarchyChanged(bool is_add,
649 View* parent,
650 View* child) {
initial.commit09911bf2008-07-26 23:55:29651}
652
653void View::ViewHierarchyChangedImpl(bool register_accelerators,
[email protected]bb515ed2009-01-15 00:53:43654 bool is_add,
655 View* parent,
656 View* child) {
initial.commit09911bf2008-07-26 23:55:29657 if (register_accelerators) {
658 if (is_add) {
659 // If you get this registration, you are part of a subtree that has been
660 // added to the view hierarchy.
[email protected]71421c3f2009-06-06 00:41:44661 RegisterPendingAccelerators();
initial.commit09911bf2008-07-26 23:55:29662 } else {
663 if (child == this)
664 UnregisterAccelerators();
665 }
666 }
667
668 ViewHierarchyChanged(is_add, parent, child);
669}
670
671void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
672 int i, c;
673 for (i = 0, c = GetChildViewCount(); i < c; ++i) {
674 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
675 }
676 VisibilityChanged(start, is_visible);
677}
678
679void View::VisibilityChanged(View* starting_from, bool is_visible) {
680}
681
initial.commit09911bf2008-07-26 23:55:29682void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
683 if (notify_when_visible_bounds_in_root_changes_ == value)
684 return;
685 notify_when_visible_bounds_in_root_changes_ = value;
686 RootView* root = GetRootView();
687 if (root) {
688 if (value)
689 root->RegisterViewForVisibleBoundsNotification(this);
690 else
691 root->UnregisterViewForVisibleBoundsNotification(this);
692 }
693}
694
695bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
696 return notify_when_visible_bounds_in_root_changes_;
697}
698
[email protected]0d52b2302009-05-11 23:50:55699View* View::GetViewForPoint(const gfx::Point& point) {
initial.commit09911bf2008-07-26 23:55:29700 // Walk the child Views recursively looking for the View that most
701 // tightly encloses the specified point.
702 for (int i = GetChildViewCount() - 1 ; i >= 0 ; --i) {
703 View* child = GetChildViewAt(i);
[email protected]82739cf2008-09-16 00:37:56704 if (!child->IsVisible())
initial.commit09911bf2008-07-26 23:55:29705 continue;
[email protected]82739cf2008-09-16 00:37:56706
[email protected]96b667d2008-10-14 20:58:44707 gfx::Point point_in_child_coords(point);
[email protected]82739cf2008-09-16 00:37:56708 View::ConvertPointToView(this, child, &point_in_child_coords);
[email protected]613b8062008-10-14 23:45:09709 if (child->HitTest(point_in_child_coords))
[email protected]0d52b2302009-05-11 23:50:55710 return child->GetViewForPoint(point_in_child_coords);
initial.commit09911bf2008-07-26 23:55:29711 }
712 return this;
713}
714
[email protected]a0dde122008-11-21 20:51:20715Widget* View::GetWidget() const {
716 // The root view holds a reference to this view hierarchy's Widget.
717 return parent_ ? parent_->GetWidget() : NULL;
initial.commit09911bf2008-07-26 23:55:29718}
719
[email protected]cd8c47902009-04-30 20:55:35720Window* View::GetWindow() const {
721 Widget* widget = GetWidget();
722 return widget ? widget->GetWindow() : NULL;
723}
724
initial.commit09911bf2008-07-26 23:55:29725// Get the containing RootView
726RootView* View::GetRootView() {
[email protected]a0dde122008-11-21 20:51:20727 Widget* widget = GetWidget();
728 return widget ? widget->GetRootView() : NULL;
initial.commit09911bf2008-07-26 23:55:29729}
730
731View* View::GetViewByID(int id) const {
732 if (id == id_)
733 return const_cast<View*>(this);
734
735 int view_count = GetChildViewCount();
736 for (int i = 0; i < view_count; ++i) {
737 View* child = GetChildViewAt(i);
738 View* view = child->GetViewByID(id);
739 if (view)
740 return view;
741 }
742 return NULL;
743}
744
745void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
746 if (group_ == group_id)
747 out->push_back(this);
748
749 int view_count = GetChildViewCount();
750 for (int i = 0; i < view_count; ++i)
751 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
752}
753
754View* View::GetSelectedViewForGroup(int group_id) {
755 std::vector<View*> views;
756 GetRootView()->GetViewsWithGroup(group_id, &views);
757 if (views.size() > 0)
758 return views[0];
759 else
760 return NULL;
761}
762
763void View::SetID(int id) {
764 id_ = id;
765}
766
767int View::GetID() const {
768 return id_;
769}
770
771void View::SetGroup(int gid) {
772 group_ = gid;
773}
774
775int View::GetGroup() const {
776 return group_;
777}
778
779void View::SetParent(View* parent) {
780 if (parent != parent_) {
781 parent_ = parent;
782 }
783}
784
785bool View::IsParentOf(View* v) const {
786 DCHECK(v);
787 View* parent = v->GetParent();
788 while (parent) {
789 if (this == parent)
790 return true;
791 parent = parent->GetParent();
792 }
793 return false;
794}
795
796int View::GetChildIndex(View* v) const {
797 for (int i = 0; i < GetChildViewCount(); i++) {
798 if (v == GetChildViewAt(i))
799 return i;
800 }
801 return -1;
802}
803
804///////////////////////////////////////////////////////////////////////////////
805//
806// View - focus
807//
808///////////////////////////////////////////////////////////////////////////////
809
810View* View::GetNextFocusableView() {
811 return next_focusable_view_;
812}
813
814View* View::GetPreviousFocusableView() {
815 return previous_focusable_view_;
816}
817
818void View::SetNextFocusableView(View* view) {
819 view->previous_focusable_view_ = this;
820 next_focusable_view_ = view;
821}
822
823void View::InitFocusSiblings(View* v, int index) {
824 int child_count = static_cast<int>(child_views_.size());
825
826 if (child_count == 0) {
827 v->next_focusable_view_ = NULL;
828 v->previous_focusable_view_ = NULL;
829 } else {
830 if (index == child_count) {
831 // We are inserting at the end, but the end of the child list may not be
832 // the last focusable element. Let's try to find an element with no next
833 // focusable element to link to.
834 View* last_focusable_view = NULL;
835 for (std::vector<View*>::iterator iter = child_views_.begin();
836 iter != child_views_.end(); ++iter) {
837 if (!(*iter)->next_focusable_view_) {
838 last_focusable_view = *iter;
839 break;
840 }
841 }
842 if (last_focusable_view == NULL) {
843 // Hum... there is a cycle in the focus list. Let's just insert ourself
844 // after the last child.
845 View* prev = child_views_[index - 1];
846 v->previous_focusable_view_ = prev;
847 v->next_focusable_view_ = prev->next_focusable_view_;
848 prev->next_focusable_view_->previous_focusable_view_ = v;
849 prev->next_focusable_view_ = v;
850 } else {
851 last_focusable_view->next_focusable_view_ = v;
852 v->next_focusable_view_ = NULL;
853 v->previous_focusable_view_ = last_focusable_view;
854 }
855 } else {
856 View* prev = child_views_[index]->GetPreviousFocusableView();
857 v->previous_focusable_view_ = prev;
858 v->next_focusable_view_ = child_views_[index];
859 if (prev)
860 prev->next_focusable_view_ = v;
861 child_views_[index]->previous_focusable_view_ = v;
862 }
863 }
864}
865
866#ifndef NDEBUG
867void View::PrintViewHierarchy() {
868 PrintViewHierarchyImp(0);
869}
870
871void View::PrintViewHierarchyImp(int indent) {
872 std::wostringstream buf;
873 int ind = indent;
874 while (ind-- > 0)
875 buf << L' ';
876 buf << UTF8ToWide(GetClassName());
877 buf << L' ';
878 buf << GetID();
879 buf << L' ';
[email protected]80f8b9f2008-10-16 18:17:47880 buf << bounds_.x() << L"," << bounds_.y() << L",";
881 buf << bounds_.right() << L"," << bounds_.bottom();
initial.commit09911bf2008-07-26 23:55:29882 buf << L' ';
883 buf << this;
884
885 LOG(INFO) << buf.str();
886 std::cout << buf.str() << std::endl;
887
888 for (int i = 0; i < GetChildViewCount(); ++i) {
889 GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
890 }
891}
892
893
894void View::PrintFocusHierarchy() {
895 PrintFocusHierarchyImp(0);
896}
897
898void View::PrintFocusHierarchyImp(int indent) {
899 std::wostringstream buf;
900 int ind = indent;
901 while (ind-- > 0)
902 buf << L' ';
903 buf << UTF8ToWide(GetClassName());
904 buf << L' ';
905 buf << GetID();
906 buf << L' ';
907 buf << GetClassName().c_str();
908 buf << L' ';
909 buf << this;
910
911 LOG(INFO) << buf.str();
912 std::cout << buf.str() << std::endl;
913
914 if (GetChildViewCount() > 0)
915 GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
916
917 View* v = GetNextFocusableView();
918 if (v)
919 v->PrintFocusHierarchyImp(indent);
920}
921#endif
922
923////////////////////////////////////////////////////////////////////////////////
924//
925// View - accelerators
926//
927////////////////////////////////////////////////////////////////////////////////
928
929void View::AddAccelerator(const Accelerator& accelerator) {
930 if (!accelerators_.get())
931 accelerators_.reset(new std::vector<Accelerator>());
[email protected]71421c3f2009-06-06 00:41:44932
933 std::vector<Accelerator>::iterator iter =
934 std::find(accelerators_->begin(), accelerators_->end(), accelerator);
935 DCHECK(iter == accelerators_->end())
936 << "Registering the same accelerator multiple times";
937
initial.commit09911bf2008-07-26 23:55:29938 accelerators_->push_back(accelerator);
[email protected]71421c3f2009-06-06 00:41:44939 RegisterPendingAccelerators();
initial.commit09911bf2008-07-26 23:55:29940}
941
[email protected]e8e0f362008-11-08 01:13:25942void View::RemoveAccelerator(const Accelerator& accelerator) {
943 std::vector<Accelerator>::iterator iter;
944 if (!accelerators_.get() ||
945 ((iter = std::find(accelerators_->begin(), accelerators_->end(),
946 accelerator)) == accelerators_->end())) {
947 NOTREACHED() << "Removing non-existing accelerator";
948 return;
949 }
950
[email protected]4bd23f32009-06-08 20:59:19951 size_t index = iter - accelerators_->begin();
[email protected]e8e0f362008-11-08 01:13:25952 accelerators_->erase(iter);
[email protected]71421c3f2009-06-06 00:41:44953 if (index >= registered_accelerator_count_) {
954 // The accelerator is not registered to FocusManager.
955 return;
956 }
957 --registered_accelerator_count_;
958
[email protected]e8e0f362008-11-08 01:13:25959 RootView* root_view = GetRootView();
960 if (!root_view) {
961 // We are not part of a view hierarchy, so there is nothing to do as we
962 // removed ourselves from accelerators_, we won't be registered when added
963 // to one.
964 return;
965 }
966
[email protected]f3735c5d2009-03-19 17:26:23967 // TODO(port): Fix this once we have a FocusManger for Linux.
968#if defined(OS_WIN)
[email protected]e8e0f362008-11-08 01:13:25969 FocusManager* focus_manager = GetFocusManager();
970 if (focus_manager) {
971 // We may not have a FocusManager if the window containing us is being
972 // closed, in which case the FocusManager is being deleted so there is
973 // nothing to unregister.
974 focus_manager->UnregisterAccelerator(accelerator, this);
975 }
[email protected]f3735c5d2009-03-19 17:26:23976#endif
[email protected]e8e0f362008-11-08 01:13:25977}
978
initial.commit09911bf2008-07-26 23:55:29979void View::ResetAccelerators() {
[email protected]71421c3f2009-06-06 00:41:44980 if (accelerators_.get())
initial.commit09911bf2008-07-26 23:55:29981 UnregisterAccelerators();
initial.commit09911bf2008-07-26 23:55:29982}
983
[email protected]71421c3f2009-06-06 00:41:44984void View::RegisterPendingAccelerators() {
985 if (!accelerators_.get() ||
986 registered_accelerator_count_ == accelerators_->size()) {
987 // No accelerators are waiting for registration.
initial.commit09911bf2008-07-26 23:55:29988 return;
[email protected]71421c3f2009-06-06 00:41:44989 }
initial.commit09911bf2008-07-26 23:55:29990
991 RootView* root_view = GetRootView();
992 if (!root_view) {
993 // We are not yet part of a view hierarchy, we'll register ourselves once
994 // added to one.
995 return;
996 }
[email protected]f3735c5d2009-03-19 17:26:23997
initial.commit09911bf2008-07-26 23:55:29998 FocusManager* focus_manager = GetFocusManager();
999 if (!focus_manager) {
1000 // Some crash reports seem to show that we may get cases where we have no
1001 // focus manager (see bug #1291225). This should never be the case, just
1002 // making sure we don't crash.
1003 NOTREACHED();
1004 return;
1005 }
[email protected]71421c3f2009-06-06 00:41:441006 std::vector<Accelerator>::const_iterator iter;
1007 for (iter = accelerators_->begin() + registered_accelerator_count_;
initial.commit09911bf2008-07-26 23:55:291008 iter != accelerators_->end(); ++iter) {
1009 focus_manager->RegisterAccelerator(*iter, this);
1010 }
[email protected]71421c3f2009-06-06 00:41:441011 registered_accelerator_count_ = accelerators_->size();
initial.commit09911bf2008-07-26 23:55:291012}
1013
1014void View::UnregisterAccelerators() {
1015 if (!accelerators_.get())
1016 return;
1017
1018 RootView* root_view = GetRootView();
1019 if (root_view) {
[email protected]f3735c5d2009-03-19 17:26:231020 // TODO(port): Fix this once we have a FocusManger for Linux.
1021#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:291022 FocusManager* focus_manager = GetFocusManager();
1023 if (focus_manager) {
1024 // We may not have a FocusManager if the window containing us is being
1025 // closed, in which case the FocusManager is being deleted so there is
1026 // nothing to unregister.
1027 focus_manager->UnregisterAccelerators(this);
1028 }
[email protected]71421c3f2009-06-06 00:41:441029 accelerators_->clear();
1030 accelerators_.reset();
1031 registered_accelerator_count_ = 0;
[email protected]f3735c5d2009-03-19 17:26:231032#endif
initial.commit09911bf2008-07-26 23:55:291033 }
1034}
1035
initial.commit09911bf2008-07-26 23:55:291036int View::GetDragOperations(int press_x, int press_y) {
1037 if (!drag_controller_)
1038 return DragDropTypes::DRAG_NONE;
1039 return drag_controller_->GetDragOperations(this, press_x, press_y);
1040}
1041
1042void View::WriteDragData(int press_x, int press_y, OSExchangeData* data) {
1043 DCHECK(drag_controller_);
1044 drag_controller_->WriteDragData(this, press_x, press_y, data);
1045}
1046
1047void View::OnDragDone() {
1048}
1049
1050bool View::InDrag() {
1051 RootView* root_view = GetRootView();
1052 return root_view ? (root_view->GetDragView() == this) : false;
1053}
1054
initial.commit09911bf2008-07-26 23:55:291055// static
[email protected]bb515ed2009-01-15 00:53:431056void View::ConvertPointToView(const View* src,
1057 const View* dst,
1058 gfx::Point* point) {
initial.commit09911bf2008-07-26 23:55:291059 ConvertPointToView(src, dst, point, true);
1060}
1061
1062// static
[email protected]bb515ed2009-01-15 00:53:431063void View::ConvertPointToView(const View* src,
1064 const View* dst,
1065 gfx::Point* point,
initial.commit09911bf2008-07-26 23:55:291066 bool try_other_direction) {
1067 // src can be NULL
1068 DCHECK(dst);
1069 DCHECK(point);
1070
[email protected]bb515ed2009-01-15 00:53:431071 const View* v;
initial.commit09911bf2008-07-26 23:55:291072 gfx::Point offset;
1073
1074 for (v = dst; v && v != src; v = v->GetParent()) {
1075 offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
[email protected]6f3bb6c2008-09-17 22:25:331076 offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291077 }
1078
1079 // The source was not found. The caller wants a conversion
1080 // from a view to a transitive parent.
1081 if (src && v == NULL && try_other_direction) {
1082 gfx::Point p;
1083 // note: try_other_direction is force to FALSE so we don't
1084 // end up in an infinite recursion should both src and dst
1085 // are not parented.
1086 ConvertPointToView(dst, src, &p, false);
1087 // since the src and dst are inverted, p should also be negated
1088 point->SetPoint(point->x() - p.x(), point->y() - p.y());
1089 } else {
1090 point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
1091
1092 // If src is NULL, sp is in the screen coordinate system
1093 if (src == NULL) {
[email protected]a0dde122008-11-21 20:51:201094 Widget* widget = dst->GetWidget();
1095 if (widget) {
[email protected]3b680a82008-12-17 02:03:231096 gfx::Rect b;
[email protected]a0dde122008-11-21 20:51:201097 widget->GetBounds(&b, false);
[email protected]3b680a82008-12-17 02:03:231098 point->SetPoint(point->x() - b.x(), point->y() - b.y());
initial.commit09911bf2008-07-26 23:55:291099 }
1100 }
1101 }
1102}
1103
1104// static
[email protected]2fb6d462009-02-13 18:40:101105void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291106 DCHECK(src);
1107 DCHECK(p);
[email protected]96b667d2008-10-14 20:58:441108
[email protected]96b667d2008-10-14 20:58:441109 gfx::Point offset;
[email protected]2fb6d462009-02-13 18:40:101110 for (const View* v = src; v; v = v->GetParent()) {
[email protected]96b667d2008-10-14 20:58:441111 offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION));
1112 offset.set_y(offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291113 }
[email protected]96b667d2008-10-14 20:58:441114 p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
initial.commit09911bf2008-07-26 23:55:291115}
1116
1117// static
[email protected]2fb6d462009-02-13 18:40:101118void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
[email protected]96b667d2008-10-14 20:58:441119 gfx::Point t;
[email protected]2fb6d462009-02-13 18:40:101120 ConvertPointToWidget(dest, &t);
[email protected]96b667d2008-10-14 20:58:441121 p->SetPoint(p->x() - t.x(), p->y() - t.y());
initial.commit09911bf2008-07-26 23:55:291122}
1123
1124// static
[email protected]2fb6d462009-02-13 18:40:101125void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291126 DCHECK(src);
1127 DCHECK(p);
1128
[email protected]96b667d2008-10-14 20:58:441129 // If the view is not connected to a tree, there's nothing we can do.
[email protected]a0dde122008-11-21 20:51:201130 Widget* widget = src->GetWidget();
1131 if (widget) {
1132 ConvertPointToWidget(src, p);
[email protected]3b680a82008-12-17 02:03:231133 gfx::Rect r;
[email protected]a0dde122008-11-21 20:51:201134 widget->GetBounds(&r, false);
[email protected]3b680a82008-12-17 02:03:231135 p->SetPoint(p->x() + r.x(), p->y() + r.y());
initial.commit09911bf2008-07-26 23:55:291136 }
1137}
1138
1139/////////////////////////////////////////////////////////////////////////////
1140//
1141// View - event handlers
1142//
1143/////////////////////////////////////////////////////////////////////////////
1144
1145bool View::OnMousePressed(const MouseEvent& e) {
1146 return false;
1147}
1148
1149bool View::OnMouseDragged(const MouseEvent& e) {
1150 return false;
1151}
1152
1153void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
1154}
1155
1156void View::OnMouseMoved(const MouseEvent& e) {
1157}
1158
1159void View::OnMouseEntered(const MouseEvent& e) {
1160}
1161
1162void View::OnMouseExited(const MouseEvent& e) {
1163}
1164
1165void View::SetMouseHandler(View *new_mouse_handler) {
1166 // It is valid for new_mouse_handler to be NULL
1167 if (parent_) {
1168 parent_->SetMouseHandler(new_mouse_handler);
1169 }
1170}
1171
1172void View::SetVisible(bool flag) {
1173 if (flag != is_visible_) {
1174 // If the tab is currently visible, schedule paint to
1175 // refresh parent
1176 if (IsVisible()) {
1177 SchedulePaint();
1178 }
1179
1180 is_visible_ = flag;
1181
1182 // This notifies all subviews recursively.
1183 PropagateVisibilityNotifications(this, flag);
1184
1185 // If we are newly visible, schedule paint.
1186 if (IsVisible()) {
1187 SchedulePaint();
1188 }
1189 }
1190}
1191
1192bool View::IsVisibleInRootView() const {
1193 View* parent = GetParent();
1194 if (IsVisible() && parent)
1195 return parent->IsVisibleInRootView();
1196 else
1197 return false;
1198}
1199
initial.commit09911bf2008-07-26 23:55:291200/////////////////////////////////////////////////////////////////////////////
1201//
1202// View - keyboard and focus
1203//
1204/////////////////////////////////////////////////////////////////////////////
1205
1206void View::RequestFocus() {
1207 RootView* rv = GetRootView();
[email protected]830e2062009-02-13 18:27:381208 if (rv && IsFocusable())
initial.commit09911bf2008-07-26 23:55:291209 rv->FocusView(this);
initial.commit09911bf2008-07-26 23:55:291210}
1211
1212void View::WillGainFocus() {
1213}
1214
1215void View::DidGainFocus() {
1216}
1217
1218void View::WillLoseFocus() {
1219}
1220
1221bool View::OnKeyPressed(const KeyEvent& e) {
1222 return false;
1223}
1224
1225bool View::OnKeyReleased(const KeyEvent& e) {
1226 return false;
1227}
1228
1229bool View::OnMouseWheel(const MouseWheelEvent& e) {
1230 return false;
1231}
1232
1233void View::SetDragController(DragController* drag_controller) {
1234 drag_controller_ = drag_controller;
1235}
1236
1237DragController* View::GetDragController() {
1238 return drag_controller_;
1239}
1240
[email protected]134c47b92009-08-19 03:33:441241bool View::GetDropFormats(
1242 int* formats,
1243 std::set<OSExchangeData::CustomFormat>* custom_formats) {
1244 return false;
1245}
1246
1247bool View::AreDropTypesRequired() {
1248 return false;
1249}
1250
initial.commit09911bf2008-07-26 23:55:291251bool View::CanDrop(const OSExchangeData& data) {
[email protected]134c47b92009-08-19 03:33:441252 // TODO(sky): when I finish up migration, this should default to true.
initial.commit09911bf2008-07-26 23:55:291253 return false;
1254}
1255
1256void View::OnDragEntered(const DropTargetEvent& event) {
1257}
1258
1259int View::OnDragUpdated(const DropTargetEvent& event) {
1260 return DragDropTypes::DRAG_NONE;
1261}
1262
1263void View::OnDragExited() {
1264}
1265
1266int View::OnPerformDrop(const DropTargetEvent& event) {
1267 return DragDropTypes::DRAG_NONE;
1268}
1269
initial.commit09911bf2008-07-26 23:55:291270// static
1271bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1272 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1273 abs(delta_y) > GetVerticalDragThreshold());
1274}
1275
initial.commit09911bf2008-07-26 23:55:291276// Tooltips -----------------------------------------------------------------
1277bool View::GetTooltipText(int x, int y, std::wstring* tooltip) {
1278 return false;
1279}
1280
[email protected]0a1d36b22008-10-17 19:33:091281bool View::GetTooltipTextOrigin(int x, int y, gfx::Point* loc) {
initial.commit09911bf2008-07-26 23:55:291282 return false;
1283}
1284
1285void View::TooltipTextChanged() {
[email protected]a0dde122008-11-21 20:51:201286 Widget* widget = GetWidget();
1287 if (widget && widget->GetTooltipManager())
1288 widget->GetTooltipManager()->TooltipTextChanged(this);
initial.commit09911bf2008-07-26 23:55:291289}
1290
1291void View::UpdateTooltip() {
[email protected]a0dde122008-11-21 20:51:201292 Widget* widget = GetWidget();
1293 if (widget && widget->GetTooltipManager())
1294 widget->GetTooltipManager()->UpdateTooltip();
initial.commit09911bf2008-07-26 23:55:291295}
1296
1297void View::SetParentOwned(bool f) {
1298 is_parent_owned_ = f;
1299}
1300
1301bool View::IsParentOwned() const {
1302 return is_parent_owned_;
1303}
1304
1305std::string View::GetClassName() const {
1306 return kViewClassName;
1307}
1308
[email protected]5c2b98b2009-03-09 20:55:541309View* View::GetAncestorWithClassName(const std::string& name) {
1310 for (View* view = this; view; view = view->GetParent()) {
1311 if (view->GetClassName() == name)
1312 return view;
1313 }
1314 return NULL;
1315}
1316
initial.commit09911bf2008-07-26 23:55:291317gfx::Rect View::GetVisibleBounds() {
[email protected]b6296fd2009-02-13 17:34:161318 if (!IsVisibleInRootView())
1319 return gfx::Rect();
[email protected]6f3bb6c2008-09-17 22:25:331320 gfx::Rect vis_bounds(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:291321 gfx::Rect ancestor_bounds;
1322 View* view = this;
1323 int root_x = 0;
1324 int root_y = 0;
initial.commit09911bf2008-07-26 23:55:291325 while (view != NULL && !vis_bounds.IsEmpty()) {
1326 root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
[email protected]6f3bb6c2008-09-17 22:25:331327 root_y += view->y();
1328 vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y());
initial.commit09911bf2008-07-26 23:55:291329 View* ancestor = view->GetParent();
1330 if (ancestor != NULL) {
[email protected]6f3bb6c2008-09-17 22:25:331331 ancestor_bounds.SetRect(0, 0, ancestor->width(),
1332 ancestor->height());
initial.commit09911bf2008-07-26 23:55:291333 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
[email protected]a0dde122008-11-21 20:51:201334 } else if (!view->GetWidget()) {
1335 // If the view has no Widget, we're not visible. Return an empty rect.
initial.commit09911bf2008-07-26 23:55:291336 return gfx::Rect();
1337 }
1338 view = ancestor;
1339 }
1340 if (vis_bounds.IsEmpty())
1341 return vis_bounds;
1342 // Convert back to this views coordinate system.
1343 vis_bounds.Offset(-root_x, -root_y);
1344 return vis_bounds;
1345}
1346
1347int View::GetPageScrollIncrement(ScrollView* scroll_view,
1348 bool is_horizontal, bool is_positive) {
1349 return 0;
1350}
1351
1352int View::GetLineScrollIncrement(ScrollView* scroll_view,
1353 bool is_horizontal, bool is_positive) {
1354 return 0;
1355}
1356
[email protected]4a190632009-05-09 01:07:421357ThemeProvider* View::GetThemeProvider() {
1358 Widget* widget = GetWidget();
1359 return widget ? widget->GetThemeProvider() : NULL;
1360}
1361
initial.commit09911bf2008-07-26 23:55:291362// static
1363void View::RegisterChildrenForVisibleBoundsNotification(
1364 RootView* root, View* view) {
1365 DCHECK(root && view);
1366 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1367 root->RegisterViewForVisibleBoundsNotification(view);
1368 for (int i = 0; i < view->GetChildViewCount(); ++i)
1369 RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i));
1370}
1371
1372// static
1373void View::UnregisterChildrenForVisibleBoundsNotification(
1374 RootView* root, View* view) {
1375 DCHECK(root && view);
1376 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1377 root->UnregisterViewForVisibleBoundsNotification(view);
1378 for (int i = 0; i < view->GetChildViewCount(); ++i)
1379 UnregisterChildrenForVisibleBoundsNotification(root,
1380 view->GetChildViewAt(i));
1381}
1382
1383void View::AddDescendantToNotify(View* view) {
1384 DCHECK(view);
1385 if (!descendants_to_notify_.get())
1386 descendants_to_notify_.reset(new ViewList());
1387 descendants_to_notify_->push_back(view);
1388}
1389
1390void View::RemoveDescendantToNotify(View* view) {
1391 DCHECK(view && descendants_to_notify_.get());
1392 ViewList::iterator i = find(descendants_to_notify_->begin(),
1393 descendants_to_notify_->end(),
1394 view);
1395 DCHECK(i != descendants_to_notify_->end());
1396 descendants_to_notify_->erase(i);
1397 if (descendants_to_notify_->empty())
1398 descendants_to_notify_.reset();
1399}
1400
initial.commit09911bf2008-07-26 23:55:291401// DropInfo --------------------------------------------------------------------
1402
1403void View::DragInfo::Reset() {
1404 possible_drag = false;
1405 start_x = start_y = 0;
1406}
1407
1408void View::DragInfo::PossibleDrag(int x, int y) {
1409 possible_drag = true;
1410 start_x = x;
1411 start_y = y;
1412}
1413
1414} // namespace