blob: d88defc71df75d23611e7dab28e81ba5504c48c4 [file] [log] [blame]
[email protected]8af4c1992010-02-04 21:38:071// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// 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]031e4d32009-12-29 01:13:2328
[email protected]6ff244f2009-01-20 20:38:0829#if defined(OS_WIN)
[email protected]2362e4f2009-05-08 00:34:0530#include "views/accessibility/view_accessibility_wrapper.h"
[email protected]6ff244f2009-01-20 20:38:0831#endif
[email protected]031e4d32009-12-29 01:13:2332#if defined(OS_LINUX)
33#include "app/scoped_handle_gtk.h"
34#endif
initial.commit09911bf2008-07-26 23:55:2935
[email protected]c2dacc92008-10-16 23:51:3836namespace views {
initial.commit09911bf2008-07-26 23:55:2937
38// static
[email protected]3ee83f2c2009-05-10 05:58:4039ViewsDelegate* ViewsDelegate::views_delegate = NULL;
40
41// static
[email protected]2362e4f2009-05-08 00:34:0542char View::kViewClassName[] = "views/View";
initial.commit09911bf2008-07-26 23:55:2943
[email protected]8af4c1992010-02-04 21:38:0744// static
45const int View::kShowFolderDropMenuDelay = 400;
46
initial.commit09911bf2008-07-26 23:55:2947/////////////////////////////////////////////////////////////////////////////
48//
49// View - constructors, destructors, initialization
50//
51/////////////////////////////////////////////////////////////////////////////
52
53View::View()
54 : id_(0),
55 group_(-1),
[email protected]6ff244f2009-01-20 20:38:0856 enabled_(true),
57 focusable_(false),
[email protected]4f3dc372009-02-24 00:10:2958 bounds_(0, 0, 0, 0),
initial.commit09911bf2008-07-26 23:55:2959 parent_(NULL),
initial.commit09911bf2008-07-26 23:55:2960 is_visible_(true),
initial.commit09911bf2008-07-26 23:55:2961 is_parent_owned_(true),
62 notify_when_visible_bounds_in_root_changes_(false),
63 registered_for_visible_bounds_notification_(false),
[email protected]bda9556c2010-01-07 00:55:1664 accelerator_registration_delayed_(false),
initial.commit09911bf2008-07-26 23:55:2965 next_focusable_view_(NULL),
66 previous_focusable_view_(NULL),
[email protected]bda9556c2010-01-07 00:55:1667 accelerator_focus_manager_(NULL),
[email protected]71421c3f2009-06-06 00:41:4468 registered_accelerator_count_(0),
initial.commit09911bf2008-07-26 23:55:2969 context_menu_controller_(NULL),
[email protected]6ff244f2009-01-20 20:38:0870#if defined(OS_WIN)
71 accessibility_(NULL),
72#endif
initial.commit09911bf2008-07-26 23:55:2973 drag_controller_(NULL),
74 ui_mirroring_is_enabled_for_rtl_languages_(true),
75 flip_canvas_on_paint_for_rtl_ui_(false) {
76}
77
78View::~View() {
initial.commit09911bf2008-07-26 23:55:2979 int c = static_cast<int>(child_views_.size());
80 while (--c >= 0) {
81 if (child_views_[c]->IsParentOwned())
82 delete child_views_[c];
83 else
84 child_views_[c]->SetParent(NULL);
85 }
[email protected]a64f33902009-10-10 05:41:2386
87#if defined(OS_WIN)
[email protected]09fe9492009-11-07 02:23:0688 if (accessibility_.get())
[email protected]a64f33902009-10-10 05:41:2389 accessibility_->Uninitialize();
[email protected]a64f33902009-10-10 05:41:2390#endif
initial.commit09911bf2008-07-26 23:55:2991}
92
93/////////////////////////////////////////////////////////////////////////////
94//
95// View - sizing
96//
97/////////////////////////////////////////////////////////////////////////////
98
[email protected]0d8ea702008-10-14 17:03:0799gfx::Rect View::GetBounds(PositionMirroringSettings settings) const {
100 gfx::Rect bounds(bounds_);
initial.commit09911bf2008-07-26 23:55:29101
102 // If the parent uses an RTL UI layout and if we are asked to transform the
103 // bounds to their mirrored position if necessary, then we should shift the
104 // rectangle appropriately.
[email protected]0d8ea702008-10-14 17:03:07105 if (settings == APPLY_MIRRORING_TRANSFORMATION)
106 bounds.set_x(MirroredX());
[email protected]4f3dc372009-02-24 00:10:29107
[email protected]0d8ea702008-10-14 17:03:07108 return bounds;
initial.commit09911bf2008-07-26 23:55:29109}
110
[email protected]6f3bb6c2008-09-17 22:25:33111// y(), width() and height() are agnostic to the RTL UI layout of the
112// parent view. x(), on the other hand, is not.
initial.commit09911bf2008-07-26 23:55:29113int View::GetX(PositionMirroringSettings settings) const {
[email protected]80f8b9f2008-10-16 18:17:47114 return settings == IGNORE_MIRRORING_TRANSFORMATION ? x() : MirroredX();
initial.commit09911bf2008-07-26 23:55:29115}
116
[email protected]80f8b9f2008-10-16 18:17:47117void View::SetBounds(const gfx::Rect& bounds) {
118 if (bounds == bounds_)
initial.commit09911bf2008-07-26 23:55:29119 return;
initial.commit09911bf2008-07-26 23:55:29120
[email protected]80f8b9f2008-10-16 18:17:47121 gfx::Rect prev = bounds_;
initial.commit09911bf2008-07-26 23:55:29122 bounds_ = bounds;
[email protected]b97c8a22010-02-05 19:36:43123 bool size_changed = prev.size() != bounds_.size();
124 bool position_changed = prev.origin() != bounds_.origin();
initial.commit09911bf2008-07-26 23:55:29125
[email protected]b97c8a22010-02-05 19:36:43126 if (size_changed || position_changed) {
127 DidChangeBounds(prev, bounds_);
128
129 RootView* root = GetRootView();
130 if (root)
initial.commit09911bf2008-07-26 23:55:29131 root->ViewBoundsChanged(this, size_changed, position_changed);
132 }
133}
134
[email protected]80f8b9f2008-10-16 18:17:47135gfx::Rect View::GetLocalBounds(bool include_border) const {
[email protected]9a3f0ac22008-11-14 03:24:02136 if (include_border || !border_.get())
[email protected]80f8b9f2008-10-16 18:17:47137 return gfx::Rect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29138
[email protected]80f8b9f2008-10-16 18:17:47139 gfx::Insets insets;
140 border_->GetInsets(&insets);
141 return gfx::Rect(insets.left(), insets.top(),
[email protected]4a8d3272009-03-10 19:15:08142 std::max(0, width() - insets.width()),
143 std::max(0, height() - insets.height()));
initial.commit09911bf2008-07-26 23:55:29144}
145
[email protected]0a1d36b22008-10-17 19:33:09146gfx::Point View::GetPosition() const {
147 return gfx::Point(GetX(APPLY_MIRRORING_TRANSFORMATION), y());
initial.commit09911bf2008-07-26 23:55:29148}
149
[email protected]154f8bc2008-10-15 18:02:30150gfx::Size View::GetPreferredSize() {
151 if (layout_manager_.get())
152 return layout_manager_->GetPreferredSize(this);
153 return gfx::Size();
initial.commit09911bf2008-07-26 23:55:29154}
155
[email protected]a1360162009-11-30 21:19:07156int View::GetBaseline() {
157 return -1;
158}
159
initial.commit09911bf2008-07-26 23:55:29160void View::SizeToPreferredSize() {
[email protected]154f8bc2008-10-15 18:02:30161 gfx::Size prefsize = GetPreferredSize();
162 if ((prefsize.width() != width()) || (prefsize.height() != height()))
163 SetBounds(x(), y(), prefsize.width(), prefsize.height());
initial.commit09911bf2008-07-26 23:55:29164}
165
[email protected]7ccc52b72009-05-08 21:09:11166void View::PreferredSizeChanged() {
167 if (parent_)
168 parent_->ChildPreferredSizeChanged(this);
169}
170
[email protected]154f8bc2008-10-15 18:02:30171gfx::Size View::GetMinimumSize() {
172 return GetPreferredSize();
initial.commit09911bf2008-07-26 23:55:29173}
174
175int View::GetHeightForWidth(int w) {
176 if (layout_manager_.get())
177 return layout_manager_->GetPreferredHeightForWidth(this, w);
[email protected]154f8bc2008-10-15 18:02:30178 return GetPreferredSize().height();
initial.commit09911bf2008-07-26 23:55:29179}
180
[email protected]80f8b9f2008-10-16 18:17:47181void View::DidChangeBounds(const gfx::Rect& previous,
182 const gfx::Rect& current) {
183 Layout();
initial.commit09911bf2008-07-26 23:55:29184}
185
[email protected]e9adf0702010-03-08 23:34:07186void View::ScrollRectToVisible(const gfx::Rect& rect) {
initial.commit09911bf2008-07-26 23:55:29187 View* parent = GetParent();
188
189 // We must take RTL UI mirroring into account when adjusting the position of
190 // the region.
[email protected]e9adf0702010-03-08 23:34:07191 if (parent) {
192 gfx::Rect scroll_rect(rect);
193 scroll_rect.Offset(GetX(APPLY_MIRRORING_TRANSFORMATION), y());
194 parent->ScrollRectToVisible(scroll_rect);
195 }
initial.commit09911bf2008-07-26 23:55:29196}
197
198/////////////////////////////////////////////////////////////////////////////
199//
200// View - layout
201//
202/////////////////////////////////////////////////////////////////////////////
203
204void View::Layout() {
205 // Layout child Views
206 if (layout_manager_.get()) {
207 layout_manager_->Layout(this);
208 SchedulePaint();
[email protected]d5c4f382009-02-24 21:47:36209 // TODO(beng): We believe the right thing to do here is return since the
210 // layout manager should be handling things, but it causes
211 // regressions (missing options from Options dialog and a hang
212 // in interactive_ui_tests).
initial.commit09911bf2008-07-26 23:55:29213 }
214
215 // Lay out contents of child Views
[email protected]09fe9492009-11-07 02:23:06216 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29217 View* child = GetChildViewAt(i);
218 child->Layout();
219 }
220}
221
222LayoutManager* View::GetLayoutManager() const {
223 return layout_manager_.get();
224}
225
226void View::SetLayoutManager(LayoutManager* layout_manager) {
[email protected]09fe9492009-11-07 02:23:06227 if (layout_manager_.get())
initial.commit09911bf2008-07-26 23:55:29228 layout_manager_->Uninstalled(this);
[email protected]09fe9492009-11-07 02:23:06229
initial.commit09911bf2008-07-26 23:55:29230 layout_manager_.reset(layout_manager);
[email protected]09fe9492009-11-07 02:23:06231 if (layout_manager_.get())
initial.commit09911bf2008-07-26 23:55:29232 layout_manager_->Installed(this);
initial.commit09911bf2008-07-26 23:55:29233}
234
[email protected]1eb89e82008-08-15 12:27:03235bool View::UILayoutIsRightToLeft() const {
236 return (ui_mirroring_is_enabled_for_rtl_languages_ &&
237 l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT);
238}
239
initial.commit09911bf2008-07-26 23:55:29240////////////////////////////////////////////////////////////////////////////////
241//
242// View - Right-to-left UI layout
243//
244////////////////////////////////////////////////////////////////////////////////
245
[email protected]c3bca422010-02-19 23:29:02246int View::MirroredX() const {
initial.commit09911bf2008-07-26 23:55:29247 View* parent = GetParent();
[email protected]aaa71da52010-02-19 21:39:24248 return parent ? parent->MirroredLeftPointForRect(bounds_) : x();
initial.commit09911bf2008-07-26 23:55:29249}
250
251int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const {
[email protected]aaa71da52010-02-19 21:39:24252 return UILayoutIsRightToLeft() ?
253 (width() - bounds.x() - bounds.width()) : bounds.x();
initial.commit09911bf2008-07-26 23:55:29254}
255
256////////////////////////////////////////////////////////////////////////////////
257//
258// View - states
259//
260////////////////////////////////////////////////////////////////////////////////
261
262bool View::IsEnabled() const {
263 return enabled_;
264}
265
266void View::SetEnabled(bool state) {
267 if (enabled_ != state) {
268 enabled_ = state;
269 SchedulePaint();
270 }
271}
272
273bool View::IsFocusable() const {
274 return focusable_ && enabled_ && is_visible_;
275}
276
277void View::SetFocusable(bool focusable) {
278 focusable_ = focusable;
279}
280
[email protected]82166b62009-06-30 18:48:00281FocusManager* View::GetFocusManager() {
282 Widget* widget = GetWidget();
283 return widget ? widget->GetFocusManager() : NULL;
284}
285
initial.commit09911bf2008-07-26 23:55:29286bool View::HasFocus() {
initial.commit09911bf2008-07-26 23:55:29287 FocusManager* focus_manager = GetFocusManager();
288 if (focus_manager)
289 return focus_manager->GetFocusedView() == this;
290 return false;
291}
292
[email protected]5c9e97a2009-09-09 23:48:30293void View::Focus() {
[email protected]7f14e1f2009-10-01 15:57:26294 // By default, we clear the native focus. This ensures that no visible native
295 // view as the focus and that we still receive keyboard inputs.
[email protected]5c9e97a2009-09-09 23:48:30296 FocusManager* focus_manager = GetFocusManager();
297 if (focus_manager)
[email protected]7f14e1f2009-10-01 15:57:26298 focus_manager->ClearNativeFocus();
[email protected]5c9e97a2009-09-09 23:48:30299}
300
initial.commit09911bf2008-07-26 23:55:29301void View::SetHotTracked(bool flag) {
302}
303
304/////////////////////////////////////////////////////////////////////////////
305//
306// View - painting
307//
308/////////////////////////////////////////////////////////////////////////////
309
[email protected]0a1d36b22008-10-17 19:33:09310void View::SchedulePaint(const gfx::Rect& r, bool urgent) {
311 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29312 return;
initial.commit09911bf2008-07-26 23:55:29313
314 if (parent_) {
315 // Translate the requested paint rect to the parent's coordinate system
316 // then pass this notification up to the parent.
[email protected]0a1d36b22008-10-17 19:33:09317 gfx::Rect paint_rect = r;
318 paint_rect.Offset(GetPosition());
initial.commit09911bf2008-07-26 23:55:29319 parent_->SchedulePaint(paint_rect, urgent);
320 }
321}
322
323void View::SchedulePaint() {
[email protected]0a1d36b22008-10-17 19:33:09324 SchedulePaint(GetLocalBounds(true), false);
initial.commit09911bf2008-07-26 23:55:29325}
326
[email protected]82522512009-05-15 07:37:29327void View::Paint(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29328 PaintBackground(canvas);
329 PaintFocusBorder(canvas);
330 PaintBorder(canvas);
331}
332
[email protected]82522512009-05-15 07:37:29333void View::PaintBackground(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02334 if (background_.get())
initial.commit09911bf2008-07-26 23:55:29335 background_->Paint(canvas, this);
336}
337
[email protected]82522512009-05-15 07:37:29338void View::PaintBorder(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02339 if (border_.get())
initial.commit09911bf2008-07-26 23:55:29340 border_->Paint(*this, canvas);
341}
342
[email protected]82522512009-05-15 07:37:29343void View::PaintFocusBorder(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29344 if (HasFocus() && IsFocusable())
[email protected]6f3bb6c2008-09-17 22:25:33345 canvas->DrawFocusRect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29346}
347
[email protected]82522512009-05-15 07:37:29348void View::PaintChildren(gfx::Canvas* canvas) {
[email protected]09fe9492009-11-07 02:23:06349 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29350 View* child = GetChildViewAt(i);
351 if (!child) {
352 NOTREACHED() << "Should not have a NULL child View for index in bounds";
353 continue;
354 }
355 child->ProcessPaint(canvas);
356 }
357}
358
[email protected]82522512009-05-15 07:37:29359void View::ProcessPaint(gfx::Canvas* canvas) {
[email protected]09fe9492009-11-07 02:23:06360 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29361 return;
initial.commit09911bf2008-07-26 23:55:29362
363 // We're going to modify the canvas, save it's state first.
364 canvas->save();
365
366 // Paint this View and its children, setting the clip rect to the bounds
367 // of this View and translating the origin to the local bounds' top left
368 // point.
369 //
370 // Note that the X (or left) position we pass to ClipRectInt takes into
371 // consideration whether or not the view uses a right-to-left layout so that
372 // we paint our view in its mirrored position if need be.
[email protected]80f8b9f2008-10-16 18:17:47373 if (canvas->ClipRectInt(MirroredX(), y(), width(), height())) {
initial.commit09911bf2008-07-26 23:55:29374 // Non-empty clip, translate the graphics such that 0,0 corresponds to
375 // where this view is located (related to its parent).
[email protected]80f8b9f2008-10-16 18:17:47376 canvas->TranslateInt(MirroredX(), y());
initial.commit09911bf2008-07-26 23:55:29377
378 // Save the state again, so that any changes don't effect PaintChildren.
379 canvas->save();
380
381 // If the View we are about to paint requested the canvas to be flipped, we
382 // should change the transform appropriately.
383 bool flip_canvas = FlipCanvasOnPaintForRTLUI();
384 if (flip_canvas) {
[email protected]6f3bb6c2008-09-17 22:25:33385 canvas->TranslateInt(width(), 0);
initial.commit09911bf2008-07-26 23:55:29386 canvas->ScaleInt(-1, 1);
387 canvas->save();
388 }
389
390 Paint(canvas);
391
392 // We must undo the canvas mirroring once the View is done painting so that
393 // we don't pass the canvas with the mirrored transform to Views that
394 // didn't request the canvas to be flipped.
[email protected]09fe9492009-11-07 02:23:06395 if (flip_canvas)
initial.commit09911bf2008-07-26 23:55:29396 canvas->restore();
[email protected]09fe9492009-11-07 02:23:06397
initial.commit09911bf2008-07-26 23:55:29398 canvas->restore();
399 PaintChildren(canvas);
400 }
401
402 // Restore the canvas's original transform.
403 canvas->restore();
404}
405
406void View::PaintNow() {
[email protected]09fe9492009-11-07 02:23:06407 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29408 return;
initial.commit09911bf2008-07-26 23:55:29409
410 View* view = GetParent();
411 if (view)
412 view->PaintNow();
413}
414
initial.commit09911bf2008-07-26 23:55:29415gfx::Insets View::GetInsets() const {
initial.commit09911bf2008-07-26 23:55:29416 gfx::Insets insets;
[email protected]9a3f0ac22008-11-14 03:24:02417 if (border_.get())
418 border_->GetInsets(&insets);
initial.commit09911bf2008-07-26 23:55:29419 return insets;
420}
421
[email protected]e9adf0702010-03-08 23:34:07422gfx::NativeCursor View::GetCursorForPoint(Event::EventType event_type,
423 const gfx::Point& p) {
[email protected]9abf8dd62009-06-04 06:40:42424 return NULL;
425}
426
[email protected]a52ca4672009-06-05 05:41:09427bool View::HitTest(const gfx::Point& l) const {
[email protected]d7fc97942009-11-20 22:07:11428 if (l.x() >= 0 && l.x() < width() && l.y() >= 0 && l.y() < height()) {
[email protected]a52ca4672009-06-05 05:41:09429 if (HasHitTestMask()) {
430 gfx::Path mask;
431 GetHitTestMask(&mask);
[email protected]a3406972009-11-04 05:05:48432 ScopedRegion rgn(mask.CreateNativeRegion());
433 // TODO: can this use SkRegion's contains instead?
[email protected]a52ca4672009-06-05 05:41:09434#if defined(OS_WIN)
[email protected]a52ca4672009-06-05 05:41:09435 return !!PtInRegion(rgn, l.x(), l.y());
[email protected]10a6e77b2009-12-31 01:03:52436#elif defined(TOOLKIT_USES_GTK)
[email protected]a3406972009-11-04 05:05:48437 return gdk_region_point_in(rgn.Get(), l.x(), l.y());
[email protected]a52ca4672009-06-05 05:41:09438#endif
439 }
440 // No mask, but inside our bounds.
441 return true;
442 }
443 // Outside our bounds.
444 return false;
445}
446
initial.commit09911bf2008-07-26 23:55:29447void View::SetContextMenuController(ContextMenuController* menu_controller) {
448 context_menu_controller_ = menu_controller;
449}
450
[email protected]e9adf0702010-03-08 23:34:07451void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) {
[email protected]042811c2008-10-31 21:31:34452 if (!context_menu_controller_)
453 return;
454
[email protected]e9adf0702010-03-08 23:34:07455 context_menu_controller_->ShowContextMenu(this, p, is_mouse_gesture);
[email protected]042811c2008-10-31 21:31:34456}
457
initial.commit09911bf2008-07-26 23:55:29458/////////////////////////////////////////////////////////////////////////////
459//
460// View - tree
461//
462/////////////////////////////////////////////////////////////////////////////
463
464bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
465 const bool enabled = enabled_;
[email protected]e9adf0702010-03-08 23:34:07466 int drag_operations =
467 (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location())) ?
468 GetDragOperations(e.location()) : 0;
469 ContextMenuController* context_menu_controller = e.IsRightMouseButton() ?
470 context_menu_controller_ : 0;
initial.commit09911bf2008-07-26 23:55:29471
472 const bool result = OnMousePressed(e);
473 // WARNING: we may have been deleted, don't use any View variables;
474
475 if (!enabled)
476 return result;
477
478 if (drag_operations != DragDropTypes::DRAG_NONE) {
[email protected]e9adf0702010-03-08 23:34:07479 drag_info->PossibleDrag(e.location());
initial.commit09911bf2008-07-26 23:55:29480 return true;
481 }
482 return !!context_menu_controller || result;
483}
484
485bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
486 // Copy the field, that way if we're deleted after drag and drop no harm is
487 // done.
488 ContextMenuController* context_menu_controller = context_menu_controller_;
489 const bool possible_drag = drag_info->possible_drag;
[email protected]e9adf0702010-03-08 23:34:07490 if (possible_drag && ExceededDragThreshold(drag_info->start_pt.x() - e.x(),
491 drag_info->start_pt.y() - e.y())) {
[email protected]b5f94de2009-12-04 07:59:00492 if (!drag_controller_ ||
[email protected]e9adf0702010-03-08 23:34:07493 drag_controller_->CanStartDrag(this, drag_info->start_pt, e.location()))
494 DoDrag(e, drag_info->start_pt);
initial.commit09911bf2008-07-26 23:55:29495 } else {
496 if (OnMouseDragged(e))
497 return true;
498 // Fall through to return value based on context menu controller.
499 }
500 // WARNING: we may have been deleted.
501 return (context_menu_controller != NULL) || possible_drag;
502}
503
504void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
505 if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
506 // Assume that if there is a context menu controller we won't be deleted
507 // from mouse released.
[email protected]96b667d2008-10-14 20:58:44508 gfx::Point location(e.location());
initial.commit09911bf2008-07-26 23:55:29509 OnMouseReleased(e, canceled);
[email protected]464fdb32009-03-19 20:25:44510 if (HitTest(location)) {
511 ConvertPointToScreen(this, &location);
[email protected]e9adf0702010-03-08 23:34:07512 ShowContextMenu(location, true);
[email protected]464fdb32009-03-19 20:25:44513 }
initial.commit09911bf2008-07-26 23:55:29514 } else {
515 OnMouseReleased(e, canceled);
516 }
517 // WARNING: we may have been deleted.
518}
519
initial.commit09911bf2008-07-26 23:55:29520void View::AddChildView(View* v) {
[email protected]0d52b2302009-05-11 23:50:55521 AddChildView(static_cast<int>(child_views_.size()), v);
initial.commit09911bf2008-07-26 23:55:29522}
523
524void View::AddChildView(int index, View* v) {
[email protected]0b2fa2b2009-12-01 01:06:12525 CHECK(v != this) << "You cannot add a view as its own child";
526
initial.commit09911bf2008-07-26 23:55:29527 // Remove the view from its current parent if any.
528 if (v->GetParent())
529 v->GetParent()->RemoveChildView(v);
530
[email protected]0d52b2302009-05-11 23:50:55531 // Sets the prev/next focus views.
532 InitFocusSiblings(v, index);
initial.commit09911bf2008-07-26 23:55:29533
534 // Let's insert the view.
535 child_views_.insert(child_views_.begin() + index, v);
536 v->SetParent(this);
537
[email protected]09fe9492009-11-07 02:23:06538 for (View* p = this; p; p = p->GetParent())
initial.commit09911bf2008-07-26 23:55:29539 p->ViewHierarchyChangedImpl(false, true, this, v);
[email protected]09fe9492009-11-07 02:23:06540
initial.commit09911bf2008-07-26 23:55:29541 v->PropagateAddNotifications(this, v);
542 UpdateTooltip();
543 RootView* root = GetRootView();
544 if (root)
545 RegisterChildrenForVisibleBoundsNotification(root, v);
546
547 if (layout_manager_.get())
548 layout_manager_->ViewAdded(this, v);
549}
550
551View* View::GetChildViewAt(int index) const {
552 return index < GetChildViewCount() ? child_views_[index] : NULL;
553}
554
555int View::GetChildViewCount() const {
556 return static_cast<int>(child_views_.size());
557}
558
559void View::RemoveChildView(View* a_view) {
560 DoRemoveChildView(a_view, true, true, false);
561}
562
563void View::RemoveAllChildViews(bool delete_views) {
564 ViewList::iterator iter;
565 while ((iter = child_views_.begin()) != child_views_.end()) {
566 DoRemoveChildView(*iter, false, false, delete_views);
567 }
568 UpdateTooltip();
569}
570
[email protected]e9adf0702010-03-08 23:34:07571void View::DoDrag(const MouseEvent& e, const gfx::Point& press_pt) {
572 int drag_operations = GetDragOperations(press_pt);
[email protected]4768c65b2009-08-28 21:42:59573 if (drag_operations == DragDropTypes::DRAG_NONE)
574 return;
575
576 OSExchangeData data;
[email protected]e9adf0702010-03-08 23:34:07577 WriteDragData(press_pt, &data);
[email protected]4768c65b2009-08-28 21:42:59578
579 // Message the RootView to do the drag and drop. That way if we're removed
580 // the RootView can detect it and avoid calling us back.
581 RootView* root_view = GetRootView();
582 root_view->StartDragForViewFromMouseEvent(this, data, drag_operations);
583}
584
initial.commit09911bf2008-07-26 23:55:29585void View::DoRemoveChildView(View* a_view,
586 bool update_focus_cycle,
587 bool update_tool_tip,
588 bool delete_removed_view) {
589#ifndef NDEBUG
590 DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
591 "during a paint, this will seriously " <<
592 "mess things up!";
593#endif
594 DCHECK(a_view);
595 const ViewList::iterator i = find(child_views_.begin(),
596 child_views_.end(),
597 a_view);
598 if (i != child_views_.end()) {
[email protected]0d52b2302009-05-11 23:50:55599 if (update_focus_cycle) {
initial.commit09911bf2008-07-26 23:55:29600 // Let's remove the view from the focus traversal.
601 View* next_focusable = a_view->next_focusable_view_;
602 View* prev_focusable = a_view->previous_focusable_view_;
603 if (prev_focusable)
604 prev_focusable->next_focusable_view_ = next_focusable;
605 if (next_focusable)
606 next_focusable->previous_focusable_view_ = prev_focusable;
607 }
608
609 RootView* root = GetRootView();
610 if (root)
611 UnregisterChildrenForVisibleBoundsNotification(root, a_view);
612 a_view->PropagateRemoveNotifications(this);
613 a_view->SetParent(NULL);
614
615 if (delete_removed_view && a_view->IsParentOwned())
616 delete a_view;
617
618 child_views_.erase(i);
619 }
620
621 if (update_tool_tip)
622 UpdateTooltip();
623
624 if (layout_manager_.get())
625 layout_manager_->ViewRemoved(this, a_view);
626}
627
628void View::PropagateRemoveNotifications(View* parent) {
[email protected]09fe9492009-11-07 02:23:06629 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29630 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
initial.commit09911bf2008-07-26 23:55:29631
[email protected]09fe9492009-11-07 02:23:06632 for (View* v = this; v; v = v->GetParent())
633 v->ViewHierarchyChangedImpl(true, false, parent, this);
initial.commit09911bf2008-07-26 23:55:29634}
635
636void View::PropagateAddNotifications(View* parent, View* child) {
[email protected]09fe9492009-11-07 02:23:06637 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29638 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
initial.commit09911bf2008-07-26 23:55:29639 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]bda9556c2010-01-07 00:55:16683 if (GetFocusManager()) {
684 RegisterPendingAccelerators();
685 } else {
686 // Delay accelerator registration until visible as we do not have
687 // focus manager until then.
688 accelerator_registration_delayed_ = true;
689 }
initial.commit09911bf2008-07-26 23:55:29690 } else {
691 if (child == this)
[email protected]fa1cf0b82010-01-15 21:49:44692 UnregisterAccelerators(true);
initial.commit09911bf2008-07-26 23:55:29693 }
694 }
695
696 ViewHierarchyChanged(is_add, parent, child);
697}
698
699void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
[email protected]09fe9492009-11-07 02:23:06700 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29701 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
initial.commit09911bf2008-07-26 23:55:29702 VisibilityChanged(start, is_visible);
703}
704
705void View::VisibilityChanged(View* starting_from, bool is_visible) {
706}
707
[email protected]bda9556c2010-01-07 00:55:16708void View::PropagateNativeViewHierarchyChanged(bool attached,
709 gfx::NativeView native_view,
710 RootView* root_view) {
711 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
712 GetChildViewAt(i)->PropagateNativeViewHierarchyChanged(attached,
713 native_view,
714 root_view);
715 NativeViewHierarchyChanged(attached, native_view, root_view);
716}
717
718void View::NativeViewHierarchyChanged(bool attached,
719 gfx::NativeView native_view,
720 RootView* root_view) {
721 FocusManager* focus_manager = GetFocusManager();
722 if (!accelerator_registration_delayed_ &&
723 accelerator_focus_manager_ &&
724 accelerator_focus_manager_ != focus_manager) {
725 UnregisterAccelerators(true);
726 accelerator_registration_delayed_ = true;
727 }
728 if (accelerator_registration_delayed_ && attached) {
729 if (focus_manager) {
730 RegisterPendingAccelerators();
731 accelerator_registration_delayed_ = false;
732 }
733 }
734}
735
initial.commit09911bf2008-07-26 23:55:29736void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
737 if (notify_when_visible_bounds_in_root_changes_ == value)
738 return;
739 notify_when_visible_bounds_in_root_changes_ = value;
740 RootView* root = GetRootView();
741 if (root) {
742 if (value)
743 root->RegisterViewForVisibleBoundsNotification(this);
744 else
745 root->UnregisterViewForVisibleBoundsNotification(this);
746 }
747}
748
749bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
750 return notify_when_visible_bounds_in_root_changes_;
751}
752
[email protected]0d52b2302009-05-11 23:50:55753View* View::GetViewForPoint(const gfx::Point& point) {
initial.commit09911bf2008-07-26 23:55:29754 // Walk the child Views recursively looking for the View that most
755 // tightly encloses the specified point.
[email protected]09fe9492009-11-07 02:23:06756 for (int i = GetChildViewCount() - 1; i >= 0; --i) {
initial.commit09911bf2008-07-26 23:55:29757 View* child = GetChildViewAt(i);
[email protected]82739cf2008-09-16 00:37:56758 if (!child->IsVisible())
initial.commit09911bf2008-07-26 23:55:29759 continue;
[email protected]82739cf2008-09-16 00:37:56760
[email protected]96b667d2008-10-14 20:58:44761 gfx::Point point_in_child_coords(point);
[email protected]82739cf2008-09-16 00:37:56762 View::ConvertPointToView(this, child, &point_in_child_coords);
[email protected]613b8062008-10-14 23:45:09763 if (child->HitTest(point_in_child_coords))
[email protected]0d52b2302009-05-11 23:50:55764 return child->GetViewForPoint(point_in_child_coords);
initial.commit09911bf2008-07-26 23:55:29765 }
766 return this;
767}
768
[email protected]a0dde122008-11-21 20:51:20769Widget* View::GetWidget() const {
770 // The root view holds a reference to this view hierarchy's Widget.
771 return parent_ ? parent_->GetWidget() : NULL;
initial.commit09911bf2008-07-26 23:55:29772}
773
[email protected]cd8c47902009-04-30 20:55:35774Window* View::GetWindow() const {
775 Widget* widget = GetWidget();
776 return widget ? widget->GetWindow() : NULL;
777}
778
[email protected]2db27be2010-02-10 22:46:47779bool View::ContainsNativeView(gfx::NativeView native_view) const {
780 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
781 if (GetChildViewAt(i)->ContainsNativeView(native_view))
782 return true;
783 }
784 return false;
785}
786
initial.commit09911bf2008-07-26 23:55:29787// Get the containing RootView
788RootView* View::GetRootView() {
[email protected]a0dde122008-11-21 20:51:20789 Widget* widget = GetWidget();
790 return widget ? widget->GetRootView() : NULL;
initial.commit09911bf2008-07-26 23:55:29791}
792
793View* View::GetViewByID(int id) const {
794 if (id == id_)
795 return const_cast<View*>(this);
796
[email protected]09fe9492009-11-07 02:23:06797 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29798 View* child = GetChildViewAt(i);
799 View* view = child->GetViewByID(id);
800 if (view)
801 return view;
802 }
803 return NULL;
804}
805
806void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
807 if (group_ == group_id)
808 out->push_back(this);
809
[email protected]09fe9492009-11-07 02:23:06810 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29811 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
812}
813
814View* View::GetSelectedViewForGroup(int group_id) {
815 std::vector<View*> views;
816 GetRootView()->GetViewsWithGroup(group_id, &views);
817 if (views.size() > 0)
818 return views[0];
819 else
820 return NULL;
821}
822
823void View::SetID(int id) {
824 id_ = id;
825}
826
827int View::GetID() const {
828 return id_;
829}
830
831void View::SetGroup(int gid) {
[email protected]96f960d2009-09-14 18:45:30832 // Don't change the group id once it's set.
833 DCHECK(group_ == -1 || group_ == gid);
initial.commit09911bf2008-07-26 23:55:29834 group_ = gid;
835}
836
837int View::GetGroup() const {
838 return group_;
839}
840
841void View::SetParent(View* parent) {
[email protected]09fe9492009-11-07 02:23:06842 if (parent != parent_)
initial.commit09911bf2008-07-26 23:55:29843 parent_ = parent;
initial.commit09911bf2008-07-26 23:55:29844}
845
846bool View::IsParentOf(View* v) const {
847 DCHECK(v);
848 View* parent = v->GetParent();
849 while (parent) {
850 if (this == parent)
851 return true;
852 parent = parent->GetParent();
853 }
854 return false;
855}
856
857int View::GetChildIndex(View* v) const {
[email protected]09fe9492009-11-07 02:23:06858 for (int i = 0, count = GetChildViewCount(); i < count; i++) {
initial.commit09911bf2008-07-26 23:55:29859 if (v == GetChildViewAt(i))
860 return i;
861 }
862 return -1;
863}
864
865///////////////////////////////////////////////////////////////////////////////
866//
867// View - focus
868//
869///////////////////////////////////////////////////////////////////////////////
870
871View* View::GetNextFocusableView() {
872 return next_focusable_view_;
873}
874
875View* View::GetPreviousFocusableView() {
876 return previous_focusable_view_;
877}
878
879void View::SetNextFocusableView(View* view) {
880 view->previous_focusable_view_ = this;
881 next_focusable_view_ = view;
882}
883
884void View::InitFocusSiblings(View* v, int index) {
885 int child_count = static_cast<int>(child_views_.size());
886
887 if (child_count == 0) {
888 v->next_focusable_view_ = NULL;
889 v->previous_focusable_view_ = NULL;
890 } else {
891 if (index == child_count) {
892 // We are inserting at the end, but the end of the child list may not be
893 // the last focusable element. Let's try to find an element with no next
894 // focusable element to link to.
895 View* last_focusable_view = NULL;
896 for (std::vector<View*>::iterator iter = child_views_.begin();
897 iter != child_views_.end(); ++iter) {
898 if (!(*iter)->next_focusable_view_) {
899 last_focusable_view = *iter;
900 break;
901 }
902 }
903 if (last_focusable_view == NULL) {
904 // Hum... there is a cycle in the focus list. Let's just insert ourself
905 // after the last child.
906 View* prev = child_views_[index - 1];
907 v->previous_focusable_view_ = prev;
908 v->next_focusable_view_ = prev->next_focusable_view_;
909 prev->next_focusable_view_->previous_focusable_view_ = v;
910 prev->next_focusable_view_ = v;
911 } else {
912 last_focusable_view->next_focusable_view_ = v;
913 v->next_focusable_view_ = NULL;
914 v->previous_focusable_view_ = last_focusable_view;
915 }
916 } else {
917 View* prev = child_views_[index]->GetPreviousFocusableView();
918 v->previous_focusable_view_ = prev;
919 v->next_focusable_view_ = child_views_[index];
920 if (prev)
921 prev->next_focusable_view_ = v;
922 child_views_[index]->previous_focusable_view_ = v;
923 }
924 }
925}
926
927#ifndef NDEBUG
928void View::PrintViewHierarchy() {
929 PrintViewHierarchyImp(0);
930}
931
932void View::PrintViewHierarchyImp(int indent) {
933 std::wostringstream buf;
934 int ind = indent;
935 while (ind-- > 0)
936 buf << L' ';
937 buf << UTF8ToWide(GetClassName());
938 buf << L' ';
939 buf << GetID();
940 buf << L' ';
[email protected]80f8b9f2008-10-16 18:17:47941 buf << bounds_.x() << L"," << bounds_.y() << L",";
942 buf << bounds_.right() << L"," << bounds_.bottom();
initial.commit09911bf2008-07-26 23:55:29943 buf << L' ';
944 buf << this;
945
946 LOG(INFO) << buf.str();
947 std::cout << buf.str() << std::endl;
948
[email protected]09fe9492009-11-07 02:23:06949 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29950 GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
initial.commit09911bf2008-07-26 23:55:29951}
952
953
954void View::PrintFocusHierarchy() {
955 PrintFocusHierarchyImp(0);
956}
957
958void View::PrintFocusHierarchyImp(int indent) {
959 std::wostringstream buf;
960 int ind = indent;
961 while (ind-- > 0)
962 buf << L' ';
963 buf << UTF8ToWide(GetClassName());
964 buf << L' ';
965 buf << GetID();
966 buf << L' ';
967 buf << GetClassName().c_str();
968 buf << L' ';
969 buf << this;
970
971 LOG(INFO) << buf.str();
972 std::cout << buf.str() << std::endl;
973
974 if (GetChildViewCount() > 0)
975 GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
976
977 View* v = GetNextFocusableView();
978 if (v)
979 v->PrintFocusHierarchyImp(indent);
980}
981#endif
982
983////////////////////////////////////////////////////////////////////////////////
984//
985// View - accelerators
986//
987////////////////////////////////////////////////////////////////////////////////
988
989void View::AddAccelerator(const Accelerator& accelerator) {
990 if (!accelerators_.get())
991 accelerators_.reset(new std::vector<Accelerator>());
[email protected]71421c3f2009-06-06 00:41:44992
993 std::vector<Accelerator>::iterator iter =
994 std::find(accelerators_->begin(), accelerators_->end(), accelerator);
995 DCHECK(iter == accelerators_->end())
996 << "Registering the same accelerator multiple times";
997
initial.commit09911bf2008-07-26 23:55:29998 accelerators_->push_back(accelerator);
[email protected]71421c3f2009-06-06 00:41:44999 RegisterPendingAccelerators();
initial.commit09911bf2008-07-26 23:55:291000}
1001
[email protected]e8e0f362008-11-08 01:13:251002void View::RemoveAccelerator(const Accelerator& accelerator) {
1003 std::vector<Accelerator>::iterator iter;
1004 if (!accelerators_.get() ||
1005 ((iter = std::find(accelerators_->begin(), accelerators_->end(),
1006 accelerator)) == accelerators_->end())) {
1007 NOTREACHED() << "Removing non-existing accelerator";
1008 return;
1009 }
1010
[email protected]4bd23f32009-06-08 20:59:191011 size_t index = iter - accelerators_->begin();
[email protected]e8e0f362008-11-08 01:13:251012 accelerators_->erase(iter);
[email protected]71421c3f2009-06-06 00:41:441013 if (index >= registered_accelerator_count_) {
1014 // The accelerator is not registered to FocusManager.
1015 return;
1016 }
1017 --registered_accelerator_count_;
1018
[email protected]e8e0f362008-11-08 01:13:251019 RootView* root_view = GetRootView();
1020 if (!root_view) {
1021 // We are not part of a view hierarchy, so there is nothing to do as we
1022 // removed ourselves from accelerators_, we won't be registered when added
1023 // to one.
1024 return;
1025 }
1026
[email protected]bda9556c2010-01-07 00:55:161027 // If accelerator_focus_manager_ is NULL then we did not registered
1028 // accelerators so there is nothing to unregister.
1029 if (accelerator_focus_manager_) {
1030 accelerator_focus_manager_->UnregisterAccelerator(accelerator, this);
[email protected]e8e0f362008-11-08 01:13:251031 }
1032}
1033
initial.commit09911bf2008-07-26 23:55:291034void View::ResetAccelerators() {
[email protected]71421c3f2009-06-06 00:41:441035 if (accelerators_.get())
[email protected]bda9556c2010-01-07 00:55:161036 UnregisterAccelerators(false);
initial.commit09911bf2008-07-26 23:55:291037}
1038
[email protected]71421c3f2009-06-06 00:41:441039void View::RegisterPendingAccelerators() {
1040 if (!accelerators_.get() ||
1041 registered_accelerator_count_ == accelerators_->size()) {
1042 // No accelerators are waiting for registration.
initial.commit09911bf2008-07-26 23:55:291043 return;
[email protected]71421c3f2009-06-06 00:41:441044 }
initial.commit09911bf2008-07-26 23:55:291045
1046 RootView* root_view = GetRootView();
1047 if (!root_view) {
1048 // We are not yet part of a view hierarchy, we'll register ourselves once
1049 // added to one.
1050 return;
1051 }
[email protected]f3735c5d2009-03-19 17:26:231052
[email protected]bda9556c2010-01-07 00:55:161053 accelerator_focus_manager_ = GetFocusManager();
1054 if (!accelerator_focus_manager_) {
initial.commit09911bf2008-07-26 23:55:291055 // Some crash reports seem to show that we may get cases where we have no
1056 // focus manager (see bug #1291225). This should never be the case, just
1057 // making sure we don't crash.
[email protected]f8dce002009-09-10 21:07:041058
1059 // TODO(jcampan): This fails for a view under WidgetGtk with TYPE_CHILD.
1060 // (see http://crbug.com/21335) reenable NOTREACHED assertion and
1061 // verify accelerators works as expected.
1062#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:291063 NOTREACHED();
[email protected]f8dce002009-09-10 21:07:041064#endif
initial.commit09911bf2008-07-26 23:55:291065 return;
1066 }
[email protected]71421c3f2009-06-06 00:41:441067 std::vector<Accelerator>::const_iterator iter;
1068 for (iter = accelerators_->begin() + registered_accelerator_count_;
initial.commit09911bf2008-07-26 23:55:291069 iter != accelerators_->end(); ++iter) {
[email protected]bda9556c2010-01-07 00:55:161070 accelerator_focus_manager_->RegisterAccelerator(*iter, this);
initial.commit09911bf2008-07-26 23:55:291071 }
[email protected]71421c3f2009-06-06 00:41:441072 registered_accelerator_count_ = accelerators_->size();
initial.commit09911bf2008-07-26 23:55:291073}
1074
[email protected]bda9556c2010-01-07 00:55:161075void View::UnregisterAccelerators(bool leave_data_intact) {
initial.commit09911bf2008-07-26 23:55:291076 if (!accelerators_.get())
1077 return;
1078
1079 RootView* root_view = GetRootView();
1080 if (root_view) {
[email protected]bda9556c2010-01-07 00:55:161081 if (accelerator_focus_manager_) {
initial.commit09911bf2008-07-26 23:55:291082 // We may not have a FocusManager if the window containing us is being
1083 // closed, in which case the FocusManager is being deleted so there is
1084 // nothing to unregister.
[email protected]bda9556c2010-01-07 00:55:161085 accelerator_focus_manager_->UnregisterAccelerators(this);
1086 accelerator_focus_manager_ = NULL;
initial.commit09911bf2008-07-26 23:55:291087 }
[email protected]bda9556c2010-01-07 00:55:161088 if (!leave_data_intact) {
1089 accelerators_->clear();
1090 accelerators_.reset();
1091 }
[email protected]71421c3f2009-06-06 00:41:441092 registered_accelerator_count_ = 0;
initial.commit09911bf2008-07-26 23:55:291093 }
1094}
1095
[email protected]e9adf0702010-03-08 23:34:071096int View::GetDragOperations(const gfx::Point& press_pt) {
1097 return drag_controller_ ?
1098 drag_controller_->GetDragOperations(this, press_pt) :
1099 DragDropTypes::DRAG_NONE;
initial.commit09911bf2008-07-26 23:55:291100}
1101
[email protected]e9adf0702010-03-08 23:34:071102void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) {
initial.commit09911bf2008-07-26 23:55:291103 DCHECK(drag_controller_);
[email protected]e9adf0702010-03-08 23:34:071104 drag_controller_->WriteDragData(this, press_pt, data);
initial.commit09911bf2008-07-26 23:55:291105}
1106
1107void View::OnDragDone() {
1108}
1109
1110bool View::InDrag() {
1111 RootView* root_view = GetRootView();
1112 return root_view ? (root_view->GetDragView() == this) : false;
1113}
1114
initial.commit09911bf2008-07-26 23:55:291115// static
[email protected]bb515ed2009-01-15 00:53:431116void View::ConvertPointToView(const View* src,
1117 const View* dst,
1118 gfx::Point* point) {
initial.commit09911bf2008-07-26 23:55:291119 ConvertPointToView(src, dst, point, true);
1120}
1121
1122// static
[email protected]bb515ed2009-01-15 00:53:431123void View::ConvertPointToView(const View* src,
1124 const View* dst,
1125 gfx::Point* point,
initial.commit09911bf2008-07-26 23:55:291126 bool try_other_direction) {
1127 // src can be NULL
1128 DCHECK(dst);
1129 DCHECK(point);
1130
[email protected]bb515ed2009-01-15 00:53:431131 const View* v;
initial.commit09911bf2008-07-26 23:55:291132 gfx::Point offset;
1133
1134 for (v = dst; v && v != src; v = v->GetParent()) {
1135 offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
[email protected]6f3bb6c2008-09-17 22:25:331136 offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291137 }
1138
1139 // The source was not found. The caller wants a conversion
1140 // from a view to a transitive parent.
1141 if (src && v == NULL && try_other_direction) {
1142 gfx::Point p;
1143 // note: try_other_direction is force to FALSE so we don't
1144 // end up in an infinite recursion should both src and dst
1145 // are not parented.
1146 ConvertPointToView(dst, src, &p, false);
1147 // since the src and dst are inverted, p should also be negated
1148 point->SetPoint(point->x() - p.x(), point->y() - p.y());
1149 } else {
1150 point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
1151
1152 // If src is NULL, sp is in the screen coordinate system
1153 if (src == NULL) {
[email protected]a0dde122008-11-21 20:51:201154 Widget* widget = dst->GetWidget();
1155 if (widget) {
[email protected]3b680a82008-12-17 02:03:231156 gfx::Rect b;
[email protected]a0dde122008-11-21 20:51:201157 widget->GetBounds(&b, false);
[email protected]3b680a82008-12-17 02:03:231158 point->SetPoint(point->x() - b.x(), point->y() - b.y());
initial.commit09911bf2008-07-26 23:55:291159 }
1160 }
1161 }
1162}
1163
1164// static
[email protected]2fb6d462009-02-13 18:40:101165void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291166 DCHECK(src);
1167 DCHECK(p);
[email protected]96b667d2008-10-14 20:58:441168
[email protected]96b667d2008-10-14 20:58:441169 gfx::Point offset;
[email protected]2fb6d462009-02-13 18:40:101170 for (const View* v = src; v; v = v->GetParent()) {
[email protected]96b667d2008-10-14 20:58:441171 offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION));
1172 offset.set_y(offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291173 }
[email protected]96b667d2008-10-14 20:58:441174 p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
initial.commit09911bf2008-07-26 23:55:291175}
1176
1177// static
[email protected]2fb6d462009-02-13 18:40:101178void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
[email protected]96b667d2008-10-14 20:58:441179 gfx::Point t;
[email protected]2fb6d462009-02-13 18:40:101180 ConvertPointToWidget(dest, &t);
[email protected]96b667d2008-10-14 20:58:441181 p->SetPoint(p->x() - t.x(), p->y() - t.y());
initial.commit09911bf2008-07-26 23:55:291182}
1183
1184// static
[email protected]2fb6d462009-02-13 18:40:101185void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291186 DCHECK(src);
1187 DCHECK(p);
1188
[email protected]96b667d2008-10-14 20:58:441189 // If the view is not connected to a tree, there's nothing we can do.
[email protected]a0dde122008-11-21 20:51:201190 Widget* widget = src->GetWidget();
1191 if (widget) {
1192 ConvertPointToWidget(src, p);
[email protected]3b680a82008-12-17 02:03:231193 gfx::Rect r;
[email protected]a0dde122008-11-21 20:51:201194 widget->GetBounds(&r, false);
[email protected]3b680a82008-12-17 02:03:231195 p->SetPoint(p->x() + r.x(), p->y() + r.y());
initial.commit09911bf2008-07-26 23:55:291196 }
1197}
1198
1199/////////////////////////////////////////////////////////////////////////////
1200//
1201// View - event handlers
1202//
1203/////////////////////////////////////////////////////////////////////////////
1204
1205bool View::OnMousePressed(const MouseEvent& e) {
1206 return false;
1207}
1208
1209bool View::OnMouseDragged(const MouseEvent& e) {
1210 return false;
1211}
1212
1213void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
1214}
1215
1216void View::OnMouseMoved(const MouseEvent& e) {
1217}
1218
1219void View::OnMouseEntered(const MouseEvent& e) {
1220}
1221
1222void View::OnMouseExited(const MouseEvent& e) {
1223}
1224
1225void View::SetMouseHandler(View *new_mouse_handler) {
1226 // It is valid for new_mouse_handler to be NULL
[email protected]09fe9492009-11-07 02:23:061227 if (parent_)
initial.commit09911bf2008-07-26 23:55:291228 parent_->SetMouseHandler(new_mouse_handler);
initial.commit09911bf2008-07-26 23:55:291229}
1230
1231void View::SetVisible(bool flag) {
1232 if (flag != is_visible_) {
1233 // If the tab is currently visible, schedule paint to
1234 // refresh parent
[email protected]09fe9492009-11-07 02:23:061235 if (IsVisible())
initial.commit09911bf2008-07-26 23:55:291236 SchedulePaint();
initial.commit09911bf2008-07-26 23:55:291237
1238 is_visible_ = flag;
1239
1240 // This notifies all subviews recursively.
1241 PropagateVisibilityNotifications(this, flag);
1242
1243 // If we are newly visible, schedule paint.
[email protected]09fe9492009-11-07 02:23:061244 if (IsVisible())
initial.commit09911bf2008-07-26 23:55:291245 SchedulePaint();
initial.commit09911bf2008-07-26 23:55:291246 }
1247}
1248
1249bool View::IsVisibleInRootView() const {
1250 View* parent = GetParent();
1251 if (IsVisible() && parent)
1252 return parent->IsVisibleInRootView();
1253 else
1254 return false;
1255}
1256
initial.commit09911bf2008-07-26 23:55:291257/////////////////////////////////////////////////////////////////////////////
1258//
1259// View - keyboard and focus
1260//
1261/////////////////////////////////////////////////////////////////////////////
1262
1263void View::RequestFocus() {
1264 RootView* rv = GetRootView();
[email protected]830e2062009-02-13 18:27:381265 if (rv && IsFocusable())
initial.commit09911bf2008-07-26 23:55:291266 rv->FocusView(this);
initial.commit09911bf2008-07-26 23:55:291267}
1268
1269void View::WillGainFocus() {
1270}
1271
1272void View::DidGainFocus() {
1273}
1274
1275void View::WillLoseFocus() {
1276}
1277
1278bool View::OnKeyPressed(const KeyEvent& e) {
1279 return false;
1280}
1281
1282bool View::OnKeyReleased(const KeyEvent& e) {
1283 return false;
1284}
1285
1286bool View::OnMouseWheel(const MouseWheelEvent& e) {
1287 return false;
1288}
1289
1290void View::SetDragController(DragController* drag_controller) {
[email protected]09fe9492009-11-07 02:23:061291 drag_controller_ = drag_controller;
initial.commit09911bf2008-07-26 23:55:291292}
1293
1294DragController* View::GetDragController() {
1295 return drag_controller_;
1296}
1297
[email protected]134c47b92009-08-19 03:33:441298bool View::GetDropFormats(
1299 int* formats,
1300 std::set<OSExchangeData::CustomFormat>* custom_formats) {
1301 return false;
1302}
1303
1304bool View::AreDropTypesRequired() {
1305 return false;
1306}
1307
initial.commit09911bf2008-07-26 23:55:291308bool View::CanDrop(const OSExchangeData& data) {
[email protected]134c47b92009-08-19 03:33:441309 // TODO(sky): when I finish up migration, this should default to true.
initial.commit09911bf2008-07-26 23:55:291310 return false;
1311}
1312
1313void View::OnDragEntered(const DropTargetEvent& event) {
1314}
1315
1316int View::OnDragUpdated(const DropTargetEvent& event) {
1317 return DragDropTypes::DRAG_NONE;
1318}
1319
1320void View::OnDragExited() {
1321}
1322
1323int View::OnPerformDrop(const DropTargetEvent& event) {
1324 return DragDropTypes::DRAG_NONE;
1325}
1326
initial.commit09911bf2008-07-26 23:55:291327// static
1328bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1329 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1330 abs(delta_y) > GetVerticalDragThreshold());
1331}
1332
initial.commit09911bf2008-07-26 23:55:291333// Tooltips -----------------------------------------------------------------
[email protected]e9adf0702010-03-08 23:34:071334bool View::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
initial.commit09911bf2008-07-26 23:55:291335 return false;
1336}
1337
[email protected]e9adf0702010-03-08 23:34:071338bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) {
initial.commit09911bf2008-07-26 23:55:291339 return false;
1340}
1341
1342void View::TooltipTextChanged() {
[email protected]a0dde122008-11-21 20:51:201343 Widget* widget = GetWidget();
1344 if (widget && widget->GetTooltipManager())
1345 widget->GetTooltipManager()->TooltipTextChanged(this);
initial.commit09911bf2008-07-26 23:55:291346}
1347
1348void View::UpdateTooltip() {
[email protected]a0dde122008-11-21 20:51:201349 Widget* widget = GetWidget();
1350 if (widget && widget->GetTooltipManager())
1351 widget->GetTooltipManager()->UpdateTooltip();
initial.commit09911bf2008-07-26 23:55:291352}
1353
initial.commit09911bf2008-07-26 23:55:291354std::string View::GetClassName() const {
1355 return kViewClassName;
1356}
1357
[email protected]5c2b98b2009-03-09 20:55:541358View* View::GetAncestorWithClassName(const std::string& name) {
1359 for (View* view = this; view; view = view->GetParent()) {
1360 if (view->GetClassName() == name)
1361 return view;
1362 }
1363 return NULL;
1364}
1365
initial.commit09911bf2008-07-26 23:55:291366gfx::Rect View::GetVisibleBounds() {
[email protected]b6296fd2009-02-13 17:34:161367 if (!IsVisibleInRootView())
1368 return gfx::Rect();
[email protected]6f3bb6c2008-09-17 22:25:331369 gfx::Rect vis_bounds(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:291370 gfx::Rect ancestor_bounds;
1371 View* view = this;
1372 int root_x = 0;
1373 int root_y = 0;
initial.commit09911bf2008-07-26 23:55:291374 while (view != NULL && !vis_bounds.IsEmpty()) {
1375 root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
[email protected]6f3bb6c2008-09-17 22:25:331376 root_y += view->y();
1377 vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y());
initial.commit09911bf2008-07-26 23:55:291378 View* ancestor = view->GetParent();
1379 if (ancestor != NULL) {
[email protected]6f3bb6c2008-09-17 22:25:331380 ancestor_bounds.SetRect(0, 0, ancestor->width(),
1381 ancestor->height());
initial.commit09911bf2008-07-26 23:55:291382 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
[email protected]a0dde122008-11-21 20:51:201383 } else if (!view->GetWidget()) {
1384 // If the view has no Widget, we're not visible. Return an empty rect.
initial.commit09911bf2008-07-26 23:55:291385 return gfx::Rect();
1386 }
1387 view = ancestor;
1388 }
1389 if (vis_bounds.IsEmpty())
1390 return vis_bounds;
1391 // Convert back to this views coordinate system.
1392 vis_bounds.Offset(-root_x, -root_y);
1393 return vis_bounds;
1394}
1395
1396int View::GetPageScrollIncrement(ScrollView* scroll_view,
1397 bool is_horizontal, bool is_positive) {
1398 return 0;
1399}
1400
1401int View::GetLineScrollIncrement(ScrollView* scroll_view,
1402 bool is_horizontal, bool is_positive) {
1403 return 0;
1404}
1405
[email protected]45da6c72009-10-28 20:45:421406ThemeProvider* View::GetThemeProvider() const {
[email protected]4a190632009-05-09 01:07:421407 Widget* widget = GetWidget();
1408 return widget ? widget->GetThemeProvider() : NULL;
1409}
1410
initial.commit09911bf2008-07-26 23:55:291411// static
1412void View::RegisterChildrenForVisibleBoundsNotification(
1413 RootView* root, View* view) {
1414 DCHECK(root && view);
1415 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1416 root->RegisterViewForVisibleBoundsNotification(view);
1417 for (int i = 0; i < view->GetChildViewCount(); ++i)
1418 RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i));
1419}
1420
1421// static
1422void View::UnregisterChildrenForVisibleBoundsNotification(
1423 RootView* root, View* view) {
1424 DCHECK(root && view);
1425 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1426 root->UnregisterViewForVisibleBoundsNotification(view);
1427 for (int i = 0; i < view->GetChildViewCount(); ++i)
1428 UnregisterChildrenForVisibleBoundsNotification(root,
1429 view->GetChildViewAt(i));
1430}
1431
1432void View::AddDescendantToNotify(View* view) {
1433 DCHECK(view);
1434 if (!descendants_to_notify_.get())
1435 descendants_to_notify_.reset(new ViewList());
1436 descendants_to_notify_->push_back(view);
1437}
1438
1439void View::RemoveDescendantToNotify(View* view) {
1440 DCHECK(view && descendants_to_notify_.get());
1441 ViewList::iterator i = find(descendants_to_notify_->begin(),
1442 descendants_to_notify_->end(),
1443 view);
1444 DCHECK(i != descendants_to_notify_->end());
1445 descendants_to_notify_->erase(i);
1446 if (descendants_to_notify_->empty())
1447 descendants_to_notify_.reset();
1448}
1449
initial.commit09911bf2008-07-26 23:55:291450// DropInfo --------------------------------------------------------------------
1451
1452void View::DragInfo::Reset() {
1453 possible_drag = false;
[email protected]e9adf0702010-03-08 23:34:071454 start_pt = gfx::Point();
initial.commit09911bf2008-07-26 23:55:291455}
1456
[email protected]e9adf0702010-03-08 23:34:071457void View::DragInfo::PossibleDrag(const gfx::Point& p) {
initial.commit09911bf2008-07-26 23:55:291458 possible_drag = true;
[email protected]e9adf0702010-03-08 23:34:071459 start_pt = p;
initial.commit09911bf2008-07-26 23:55:291460}
1461
1462} // namespace