blob: 5cb4f0ee8aa2da7c8d30b554c496380a3bf67caa [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"
initial.commit09911bf2008-07-26 23:55:2913#include "base/logging.h"
14#include "base/message_loop.h"
[email protected]82739cf2008-09-16 00:37:5615#include "base/scoped_handle.h"
[email protected]d55194ca2010-03-11 18:25:4516#include "base/utf_string_conversions.h"
[email protected]d07b6b52010-03-23 04:05:0117#include "gfx/canvas.h"
[email protected]5c7293a2010-03-17 06:40:5718#include "gfx/path.h"
[email protected]d5282e72009-05-13 13:16:5219#include "third_party/skia/include/core/SkShader.h"
[email protected]2362e4f2009-05-08 00:34:0520#include "views/background.h"
21#include "views/layout_manager.h"
[email protected]3ee83f2c2009-05-10 05:58:4022#include "views/views_delegate.h"
[email protected]2362e4f2009-05-08 00:34:0523#include "views/widget/root_view.h"
[email protected]319d4ae2009-05-28 19:09:4524#include "views/widget/tooltip_manager.h"
[email protected]2362e4f2009-05-08 00:34:0525#include "views/widget/widget.h"
26#include "views/window/window.h"
[email protected]031e4d32009-12-29 01:13:2327
[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
[email protected]031e4d32009-12-29 01:13:2331#if defined(OS_LINUX)
32#include "app/scoped_handle_gtk.h"
33#endif
initial.commit09911bf2008-07-26 23:55:2934
[email protected]c2dacc92008-10-16 23:51:3835namespace views {
initial.commit09911bf2008-07-26 23:55:2936
37// static
[email protected]3ee83f2c2009-05-10 05:58:4038ViewsDelegate* ViewsDelegate::views_delegate = NULL;
39
40// static
[email protected]2362e4f2009-05-08 00:34:0541char View::kViewClassName[] = "views/View";
initial.commit09911bf2008-07-26 23:55:2942
[email protected]8af4c1992010-02-04 21:38:0743// static
44const int View::kShowFolderDropMenuDelay = 400;
45
initial.commit09911bf2008-07-26 23:55:2946/////////////////////////////////////////////////////////////////////////////
47//
48// View - constructors, destructors, initialization
49//
50/////////////////////////////////////////////////////////////////////////////
51
52View::View()
53 : id_(0),
54 group_(-1),
[email protected]6ff244f2009-01-20 20:38:0855 enabled_(true),
56 focusable_(false),
[email protected]4f3dc372009-02-24 00:10:2957 bounds_(0, 0, 0, 0),
initial.commit09911bf2008-07-26 23:55:2958 parent_(NULL),
initial.commit09911bf2008-07-26 23:55:2959 is_visible_(true),
initial.commit09911bf2008-07-26 23:55:2960 is_parent_owned_(true),
61 notify_when_visible_bounds_in_root_changes_(false),
62 registered_for_visible_bounds_notification_(false),
[email protected]bda9556c2010-01-07 00:55:1663 accelerator_registration_delayed_(false),
initial.commit09911bf2008-07-26 23:55:2964 next_focusable_view_(NULL),
65 previous_focusable_view_(NULL),
[email protected]bda9556c2010-01-07 00:55:1666 accelerator_focus_manager_(NULL),
[email protected]71421c3f2009-06-06 00:41:4467 registered_accelerator_count_(0),
initial.commit09911bf2008-07-26 23:55:2968 context_menu_controller_(NULL),
[email protected]6ff244f2009-01-20 20:38:0869#if defined(OS_WIN)
70 accessibility_(NULL),
71#endif
initial.commit09911bf2008-07-26 23:55:2972 drag_controller_(NULL),
initial.commit09911bf2008-07-26 23:55:2973 flip_canvas_on_paint_for_rtl_ui_(false) {
74}
75
76View::~View() {
[email protected]8c57de22010-03-12 21:06:0477 if (parent_)
78 parent_->RemoveChildView(this);
79
initial.commit09911bf2008-07-26 23:55:2980 int c = static_cast<int>(child_views_.size());
81 while (--c >= 0) {
[email protected]8c57de22010-03-12 21:06:0482 child_views_[c]->SetParent(NULL);
initial.commit09911bf2008-07-26 23:55:2983 if (child_views_[c]->IsParentOwned())
84 delete child_views_[c];
initial.commit09911bf2008-07-26 23:55:2985 }
[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
235////////////////////////////////////////////////////////////////////////////////
236//
237// View - Right-to-left UI layout
238//
239////////////////////////////////////////////////////////////////////////////////
240
[email protected]c3bca422010-02-19 23:29:02241int View::MirroredX() const {
initial.commit09911bf2008-07-26 23:55:29242 View* parent = GetParent();
[email protected]aaa71da52010-02-19 21:39:24243 return parent ? parent->MirroredLeftPointForRect(bounds_) : x();
initial.commit09911bf2008-07-26 23:55:29244}
245
246int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const {
[email protected]c2f4bdb72010-05-10 23:15:21247 return base::i18n::IsRTL() ?
[email protected]aaa71da52010-02-19 21:39:24248 (width() - bounds.x() - bounds.width()) : bounds.x();
initial.commit09911bf2008-07-26 23:55:29249}
250
251////////////////////////////////////////////////////////////////////////////////
252//
253// View - states
254//
255////////////////////////////////////////////////////////////////////////////////
256
257bool View::IsEnabled() const {
258 return enabled_;
259}
260
261void View::SetEnabled(bool state) {
262 if (enabled_ != state) {
263 enabled_ = state;
264 SchedulePaint();
265 }
266}
267
268bool View::IsFocusable() const {
269 return focusable_ && enabled_ && is_visible_;
270}
271
272void View::SetFocusable(bool focusable) {
273 focusable_ = focusable;
274}
275
[email protected]82166b62009-06-30 18:48:00276FocusManager* View::GetFocusManager() {
277 Widget* widget = GetWidget();
278 return widget ? widget->GetFocusManager() : NULL;
279}
280
initial.commit09911bf2008-07-26 23:55:29281bool View::HasFocus() {
initial.commit09911bf2008-07-26 23:55:29282 FocusManager* focus_manager = GetFocusManager();
283 if (focus_manager)
284 return focus_manager->GetFocusedView() == this;
285 return false;
286}
287
[email protected]5c9e97a2009-09-09 23:48:30288void View::Focus() {
[email protected]7f14e1f2009-10-01 15:57:26289 // By default, we clear the native focus. This ensures that no visible native
290 // view as the focus and that we still receive keyboard inputs.
[email protected]5c9e97a2009-09-09 23:48:30291 FocusManager* focus_manager = GetFocusManager();
292 if (focus_manager)
[email protected]7f14e1f2009-10-01 15:57:26293 focus_manager->ClearNativeFocus();
[email protected]5c9e97a2009-09-09 23:48:30294}
295
initial.commit09911bf2008-07-26 23:55:29296void View::SetHotTracked(bool flag) {
297}
298
299/////////////////////////////////////////////////////////////////////////////
300//
301// View - painting
302//
303/////////////////////////////////////////////////////////////////////////////
304
[email protected]0a1d36b22008-10-17 19:33:09305void View::SchedulePaint(const gfx::Rect& r, bool urgent) {
306 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29307 return;
initial.commit09911bf2008-07-26 23:55:29308
309 if (parent_) {
310 // Translate the requested paint rect to the parent's coordinate system
311 // then pass this notification up to the parent.
[email protected]0a1d36b22008-10-17 19:33:09312 gfx::Rect paint_rect = r;
313 paint_rect.Offset(GetPosition());
initial.commit09911bf2008-07-26 23:55:29314 parent_->SchedulePaint(paint_rect, urgent);
315 }
316}
317
318void View::SchedulePaint() {
[email protected]0a1d36b22008-10-17 19:33:09319 SchedulePaint(GetLocalBounds(true), false);
initial.commit09911bf2008-07-26 23:55:29320}
321
[email protected]82522512009-05-15 07:37:29322void View::Paint(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29323 PaintBackground(canvas);
324 PaintFocusBorder(canvas);
325 PaintBorder(canvas);
326}
327
[email protected]82522512009-05-15 07:37:29328void View::PaintBackground(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02329 if (background_.get())
initial.commit09911bf2008-07-26 23:55:29330 background_->Paint(canvas, this);
331}
332
[email protected]82522512009-05-15 07:37:29333void View::PaintBorder(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02334 if (border_.get())
initial.commit09911bf2008-07-26 23:55:29335 border_->Paint(*this, canvas);
336}
337
[email protected]82522512009-05-15 07:37:29338void View::PaintFocusBorder(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29339 if (HasFocus() && IsFocusable())
[email protected]6f3bb6c2008-09-17 22:25:33340 canvas->DrawFocusRect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29341}
342
[email protected]82522512009-05-15 07:37:29343void View::PaintChildren(gfx::Canvas* canvas) {
[email protected]09fe9492009-11-07 02:23:06344 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29345 View* child = GetChildViewAt(i);
346 if (!child) {
347 NOTREACHED() << "Should not have a NULL child View for index in bounds";
348 continue;
349 }
350 child->ProcessPaint(canvas);
351 }
352}
353
[email protected]82522512009-05-15 07:37:29354void View::ProcessPaint(gfx::Canvas* canvas) {
[email protected]09fe9492009-11-07 02:23:06355 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29356 return;
initial.commit09911bf2008-07-26 23:55:29357
358 // We're going to modify the canvas, save it's state first.
359 canvas->save();
360
361 // Paint this View and its children, setting the clip rect to the bounds
362 // of this View and translating the origin to the local bounds' top left
363 // point.
364 //
365 // Note that the X (or left) position we pass to ClipRectInt takes into
366 // consideration whether or not the view uses a right-to-left layout so that
367 // we paint our view in its mirrored position if need be.
[email protected]80f8b9f2008-10-16 18:17:47368 if (canvas->ClipRectInt(MirroredX(), y(), width(), height())) {
initial.commit09911bf2008-07-26 23:55:29369 // Non-empty clip, translate the graphics such that 0,0 corresponds to
370 // where this view is located (related to its parent).
[email protected]80f8b9f2008-10-16 18:17:47371 canvas->TranslateInt(MirroredX(), y());
initial.commit09911bf2008-07-26 23:55:29372
373 // Save the state again, so that any changes don't effect PaintChildren.
374 canvas->save();
375
376 // If the View we are about to paint requested the canvas to be flipped, we
377 // should change the transform appropriately.
378 bool flip_canvas = FlipCanvasOnPaintForRTLUI();
379 if (flip_canvas) {
[email protected]6f3bb6c2008-09-17 22:25:33380 canvas->TranslateInt(width(), 0);
initial.commit09911bf2008-07-26 23:55:29381 canvas->ScaleInt(-1, 1);
382 canvas->save();
383 }
384
385 Paint(canvas);
386
387 // We must undo the canvas mirroring once the View is done painting so that
388 // we don't pass the canvas with the mirrored transform to Views that
389 // didn't request the canvas to be flipped.
[email protected]09fe9492009-11-07 02:23:06390 if (flip_canvas)
initial.commit09911bf2008-07-26 23:55:29391 canvas->restore();
[email protected]09fe9492009-11-07 02:23:06392
initial.commit09911bf2008-07-26 23:55:29393 canvas->restore();
394 PaintChildren(canvas);
395 }
396
397 // Restore the canvas's original transform.
398 canvas->restore();
399}
400
401void View::PaintNow() {
[email protected]09fe9492009-11-07 02:23:06402 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29403 return;
initial.commit09911bf2008-07-26 23:55:29404
405 View* view = GetParent();
406 if (view)
407 view->PaintNow();
408}
409
initial.commit09911bf2008-07-26 23:55:29410gfx::Insets View::GetInsets() const {
initial.commit09911bf2008-07-26 23:55:29411 gfx::Insets insets;
[email protected]9a3f0ac22008-11-14 03:24:02412 if (border_.get())
413 border_->GetInsets(&insets);
initial.commit09911bf2008-07-26 23:55:29414 return insets;
415}
416
[email protected]e9adf0702010-03-08 23:34:07417gfx::NativeCursor View::GetCursorForPoint(Event::EventType event_type,
418 const gfx::Point& p) {
[email protected]9abf8dd62009-06-04 06:40:42419 return NULL;
420}
421
[email protected]a52ca4672009-06-05 05:41:09422bool View::HitTest(const gfx::Point& l) const {
[email protected]d7fc97942009-11-20 22:07:11423 if (l.x() >= 0 && l.x() < width() && l.y() >= 0 && l.y() < height()) {
[email protected]a52ca4672009-06-05 05:41:09424 if (HasHitTestMask()) {
425 gfx::Path mask;
426 GetHitTestMask(&mask);
[email protected]a3406972009-11-04 05:05:48427 ScopedRegion rgn(mask.CreateNativeRegion());
428 // TODO: can this use SkRegion's contains instead?
[email protected]a52ca4672009-06-05 05:41:09429#if defined(OS_WIN)
[email protected]a52ca4672009-06-05 05:41:09430 return !!PtInRegion(rgn, l.x(), l.y());
[email protected]10a6e77b2009-12-31 01:03:52431#elif defined(TOOLKIT_USES_GTK)
[email protected]a3406972009-11-04 05:05:48432 return gdk_region_point_in(rgn.Get(), l.x(), l.y());
[email protected]a52ca4672009-06-05 05:41:09433#endif
434 }
435 // No mask, but inside our bounds.
436 return true;
437 }
438 // Outside our bounds.
439 return false;
440}
441
initial.commit09911bf2008-07-26 23:55:29442void View::SetContextMenuController(ContextMenuController* menu_controller) {
443 context_menu_controller_ = menu_controller;
444}
445
[email protected]e9adf0702010-03-08 23:34:07446void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) {
[email protected]042811c2008-10-31 21:31:34447 if (!context_menu_controller_)
448 return;
449
[email protected]e9adf0702010-03-08 23:34:07450 context_menu_controller_->ShowContextMenu(this, p, is_mouse_gesture);
[email protected]042811c2008-10-31 21:31:34451}
452
initial.commit09911bf2008-07-26 23:55:29453/////////////////////////////////////////////////////////////////////////////
454//
455// View - tree
456//
457/////////////////////////////////////////////////////////////////////////////
458
459bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
460 const bool enabled = enabled_;
[email protected]e9adf0702010-03-08 23:34:07461 int drag_operations =
462 (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location())) ?
463 GetDragOperations(e.location()) : 0;
464 ContextMenuController* context_menu_controller = e.IsRightMouseButton() ?
465 context_menu_controller_ : 0;
initial.commit09911bf2008-07-26 23:55:29466
467 const bool result = OnMousePressed(e);
468 // WARNING: we may have been deleted, don't use any View variables;
469
470 if (!enabled)
471 return result;
472
473 if (drag_operations != DragDropTypes::DRAG_NONE) {
[email protected]e9adf0702010-03-08 23:34:07474 drag_info->PossibleDrag(e.location());
initial.commit09911bf2008-07-26 23:55:29475 return true;
476 }
477 return !!context_menu_controller || result;
478}
479
480bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
481 // Copy the field, that way if we're deleted after drag and drop no harm is
482 // done.
483 ContextMenuController* context_menu_controller = context_menu_controller_;
484 const bool possible_drag = drag_info->possible_drag;
[email protected]e9adf0702010-03-08 23:34:07485 if (possible_drag && ExceededDragThreshold(drag_info->start_pt.x() - e.x(),
486 drag_info->start_pt.y() - e.y())) {
[email protected]b5f94de2009-12-04 07:59:00487 if (!drag_controller_ ||
[email protected]e9adf0702010-03-08 23:34:07488 drag_controller_->CanStartDrag(this, drag_info->start_pt, e.location()))
489 DoDrag(e, drag_info->start_pt);
initial.commit09911bf2008-07-26 23:55:29490 } else {
491 if (OnMouseDragged(e))
492 return true;
493 // Fall through to return value based on context menu controller.
494 }
495 // WARNING: we may have been deleted.
496 return (context_menu_controller != NULL) || possible_drag;
497}
498
499void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
500 if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
501 // Assume that if there is a context menu controller we won't be deleted
502 // from mouse released.
[email protected]96b667d2008-10-14 20:58:44503 gfx::Point location(e.location());
initial.commit09911bf2008-07-26 23:55:29504 OnMouseReleased(e, canceled);
[email protected]464fdb32009-03-19 20:25:44505 if (HitTest(location)) {
506 ConvertPointToScreen(this, &location);
[email protected]e9adf0702010-03-08 23:34:07507 ShowContextMenu(location, true);
[email protected]464fdb32009-03-19 20:25:44508 }
initial.commit09911bf2008-07-26 23:55:29509 } else {
510 OnMouseReleased(e, canceled);
511 }
512 // WARNING: we may have been deleted.
513}
514
initial.commit09911bf2008-07-26 23:55:29515void View::AddChildView(View* v) {
[email protected]0d52b2302009-05-11 23:50:55516 AddChildView(static_cast<int>(child_views_.size()), v);
initial.commit09911bf2008-07-26 23:55:29517}
518
519void View::AddChildView(int index, View* v) {
[email protected]0b2fa2b2009-12-01 01:06:12520 CHECK(v != this) << "You cannot add a view as its own child";
521
initial.commit09911bf2008-07-26 23:55:29522 // Remove the view from its current parent if any.
523 if (v->GetParent())
524 v->GetParent()->RemoveChildView(v);
525
[email protected]0d52b2302009-05-11 23:50:55526 // Sets the prev/next focus views.
527 InitFocusSiblings(v, index);
initial.commit09911bf2008-07-26 23:55:29528
529 // Let's insert the view.
530 child_views_.insert(child_views_.begin() + index, v);
531 v->SetParent(this);
532
[email protected]09fe9492009-11-07 02:23:06533 for (View* p = this; p; p = p->GetParent())
initial.commit09911bf2008-07-26 23:55:29534 p->ViewHierarchyChangedImpl(false, true, this, v);
[email protected]09fe9492009-11-07 02:23:06535
initial.commit09911bf2008-07-26 23:55:29536 v->PropagateAddNotifications(this, v);
537 UpdateTooltip();
538 RootView* root = GetRootView();
539 if (root)
540 RegisterChildrenForVisibleBoundsNotification(root, v);
541
542 if (layout_manager_.get())
543 layout_manager_->ViewAdded(this, v);
544}
545
546View* View::GetChildViewAt(int index) const {
547 return index < GetChildViewCount() ? child_views_[index] : NULL;
548}
549
550int View::GetChildViewCount() const {
551 return static_cast<int>(child_views_.size());
552}
553
[email protected]3a9c26f2010-03-12 21:04:39554bool View::HasChildView(View* a_view) {
555 return find(child_views_.begin(),
556 child_views_.end(),
557 a_view) != child_views_.end();
558}
559
initial.commit09911bf2008-07-26 23:55:29560void View::RemoveChildView(View* a_view) {
561 DoRemoveChildView(a_view, true, true, false);
562}
563
564void View::RemoveAllChildViews(bool delete_views) {
565 ViewList::iterator iter;
566 while ((iter = child_views_.begin()) != child_views_.end()) {
567 DoRemoveChildView(*iter, false, false, delete_views);
568 }
569 UpdateTooltip();
570}
571
[email protected]e9adf0702010-03-08 23:34:07572void View::DoDrag(const MouseEvent& e, const gfx::Point& press_pt) {
573 int drag_operations = GetDragOperations(press_pt);
[email protected]4768c65b2009-08-28 21:42:59574 if (drag_operations == DragDropTypes::DRAG_NONE)
575 return;
576
577 OSExchangeData data;
[email protected]e9adf0702010-03-08 23:34:07578 WriteDragData(press_pt, &data);
[email protected]4768c65b2009-08-28 21:42:59579
580 // Message the RootView to do the drag and drop. That way if we're removed
581 // the RootView can detect it and avoid calling us back.
582 RootView* root_view = GetRootView();
583 root_view->StartDragForViewFromMouseEvent(this, data, drag_operations);
584}
585
initial.commit09911bf2008-07-26 23:55:29586void View::DoRemoveChildView(View* a_view,
587 bool update_focus_cycle,
588 bool update_tool_tip,
589 bool delete_removed_view) {
590#ifndef NDEBUG
591 DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
592 "during a paint, this will seriously " <<
593 "mess things up!";
594#endif
595 DCHECK(a_view);
596 const ViewList::iterator i = find(child_views_.begin(),
597 child_views_.end(),
598 a_view);
599 if (i != child_views_.end()) {
[email protected]0d52b2302009-05-11 23:50:55600 if (update_focus_cycle) {
initial.commit09911bf2008-07-26 23:55:29601 // Let's remove the view from the focus traversal.
602 View* next_focusable = a_view->next_focusable_view_;
603 View* prev_focusable = a_view->previous_focusable_view_;
604 if (prev_focusable)
605 prev_focusable->next_focusable_view_ = next_focusable;
606 if (next_focusable)
607 next_focusable->previous_focusable_view_ = prev_focusable;
608 }
609
610 RootView* root = GetRootView();
611 if (root)
612 UnregisterChildrenForVisibleBoundsNotification(root, a_view);
613 a_view->PropagateRemoveNotifications(this);
614 a_view->SetParent(NULL);
615
616 if (delete_removed_view && a_view->IsParentOwned())
617 delete a_view;
618
619 child_views_.erase(i);
620 }
621
622 if (update_tool_tip)
623 UpdateTooltip();
624
625 if (layout_manager_.get())
626 layout_manager_->ViewRemoved(this, a_view);
627}
628
629void View::PropagateRemoveNotifications(View* parent) {
[email protected]09fe9492009-11-07 02:23:06630 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29631 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
initial.commit09911bf2008-07-26 23:55:29632
[email protected]09fe9492009-11-07 02:23:06633 for (View* v = this; v; v = v->GetParent())
634 v->ViewHierarchyChangedImpl(true, false, parent, this);
initial.commit09911bf2008-07-26 23:55:29635}
636
637void View::PropagateAddNotifications(View* parent, View* child) {
[email protected]09fe9492009-11-07 02:23:06638 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29639 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
initial.commit09911bf2008-07-26 23:55:29640 ViewHierarchyChangedImpl(true, true, parent, child);
641}
642
[email protected]32670b02009-03-03 00:28:00643void View::ThemeChanged() {
[email protected]b2b718012010-03-25 15:09:06644 for (int i = GetChildViewCount() - 1; i >= 0; --i)
[email protected]32670b02009-03-03 00:28:00645 GetChildViewAt(i)->ThemeChanged();
646}
647
[email protected]7ceeba72010-04-20 18:22:12648void View::NotifyLocaleChanged() {
649 LocaleChanged();
[email protected]b2b718012010-03-25 15:09:06650 for (int i = GetChildViewCount() - 1; i >= 0; --i)
[email protected]7ceeba72010-04-20 18:22:12651 GetChildViewAt(i)->NotifyLocaleChanged();
[email protected]b2b718012010-03-25 15:09:06652}
653
initial.commit09911bf2008-07-26 23:55:29654#ifndef NDEBUG
655bool View::IsProcessingPaint() const {
656 return GetParent() && GetParent()->IsProcessingPaint();
657}
658#endif
659
[email protected]f704ee72008-11-10 21:31:59660gfx::Point View::GetKeyboardContextMenuLocation() {
661 gfx::Rect vis_bounds = GetVisibleBounds();
662 gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
663 vis_bounds.y() + vis_bounds.height() / 2);
664 ConvertPointToScreen(this, &screen_point);
665 return screen_point;
666}
667
[email protected]82739cf2008-09-16 00:37:56668bool View::HasHitTestMask() const {
669 return false;
670}
671
672void View::GetHitTestMask(gfx::Path* mask) const {
673 DCHECK(mask);
674}
675
[email protected]bb515ed2009-01-15 00:53:43676void View::ViewHierarchyChanged(bool is_add,
677 View* parent,
678 View* child) {
initial.commit09911bf2008-07-26 23:55:29679}
680
681void View::ViewHierarchyChangedImpl(bool register_accelerators,
[email protected]bb515ed2009-01-15 00:53:43682 bool is_add,
683 View* parent,
684 View* child) {
initial.commit09911bf2008-07-26 23:55:29685 if (register_accelerators) {
686 if (is_add) {
687 // If you get this registration, you are part of a subtree that has been
688 // added to the view hierarchy.
[email protected]bda9556c2010-01-07 00:55:16689 if (GetFocusManager()) {
690 RegisterPendingAccelerators();
691 } else {
692 // Delay accelerator registration until visible as we do not have
693 // focus manager until then.
694 accelerator_registration_delayed_ = true;
695 }
initial.commit09911bf2008-07-26 23:55:29696 } else {
697 if (child == this)
[email protected]fa1cf0b82010-01-15 21:49:44698 UnregisterAccelerators(true);
initial.commit09911bf2008-07-26 23:55:29699 }
700 }
701
702 ViewHierarchyChanged(is_add, parent, child);
703}
704
705void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
[email protected]09fe9492009-11-07 02:23:06706 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29707 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
initial.commit09911bf2008-07-26 23:55:29708 VisibilityChanged(start, is_visible);
709}
710
711void View::VisibilityChanged(View* starting_from, bool is_visible) {
712}
713
[email protected]bda9556c2010-01-07 00:55:16714void View::PropagateNativeViewHierarchyChanged(bool attached,
715 gfx::NativeView native_view,
716 RootView* root_view) {
717 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
718 GetChildViewAt(i)->PropagateNativeViewHierarchyChanged(attached,
719 native_view,
720 root_view);
721 NativeViewHierarchyChanged(attached, native_view, root_view);
722}
723
724void View::NativeViewHierarchyChanged(bool attached,
725 gfx::NativeView native_view,
726 RootView* root_view) {
727 FocusManager* focus_manager = GetFocusManager();
728 if (!accelerator_registration_delayed_ &&
729 accelerator_focus_manager_ &&
730 accelerator_focus_manager_ != focus_manager) {
731 UnregisterAccelerators(true);
732 accelerator_registration_delayed_ = true;
733 }
734 if (accelerator_registration_delayed_ && attached) {
735 if (focus_manager) {
736 RegisterPendingAccelerators();
737 accelerator_registration_delayed_ = false;
738 }
739 }
740}
741
initial.commit09911bf2008-07-26 23:55:29742void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
743 if (notify_when_visible_bounds_in_root_changes_ == value)
744 return;
745 notify_when_visible_bounds_in_root_changes_ = value;
746 RootView* root = GetRootView();
747 if (root) {
748 if (value)
749 root->RegisterViewForVisibleBoundsNotification(this);
750 else
751 root->UnregisterViewForVisibleBoundsNotification(this);
752 }
753}
754
755bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
756 return notify_when_visible_bounds_in_root_changes_;
757}
758
[email protected]0d52b2302009-05-11 23:50:55759View* View::GetViewForPoint(const gfx::Point& point) {
initial.commit09911bf2008-07-26 23:55:29760 // Walk the child Views recursively looking for the View that most
761 // tightly encloses the specified point.
[email protected]09fe9492009-11-07 02:23:06762 for (int i = GetChildViewCount() - 1; i >= 0; --i) {
initial.commit09911bf2008-07-26 23:55:29763 View* child = GetChildViewAt(i);
[email protected]82739cf2008-09-16 00:37:56764 if (!child->IsVisible())
initial.commit09911bf2008-07-26 23:55:29765 continue;
[email protected]82739cf2008-09-16 00:37:56766
[email protected]96b667d2008-10-14 20:58:44767 gfx::Point point_in_child_coords(point);
[email protected]82739cf2008-09-16 00:37:56768 View::ConvertPointToView(this, child, &point_in_child_coords);
[email protected]613b8062008-10-14 23:45:09769 if (child->HitTest(point_in_child_coords))
[email protected]0d52b2302009-05-11 23:50:55770 return child->GetViewForPoint(point_in_child_coords);
initial.commit09911bf2008-07-26 23:55:29771 }
772 return this;
773}
774
[email protected]a0dde122008-11-21 20:51:20775Widget* View::GetWidget() const {
776 // The root view holds a reference to this view hierarchy's Widget.
777 return parent_ ? parent_->GetWidget() : NULL;
initial.commit09911bf2008-07-26 23:55:29778}
779
[email protected]cd8c47902009-04-30 20:55:35780Window* View::GetWindow() const {
781 Widget* widget = GetWidget();
782 return widget ? widget->GetWindow() : NULL;
783}
784
[email protected]2db27be2010-02-10 22:46:47785bool View::ContainsNativeView(gfx::NativeView native_view) const {
786 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
787 if (GetChildViewAt(i)->ContainsNativeView(native_view))
788 return true;
789 }
790 return false;
791}
792
initial.commit09911bf2008-07-26 23:55:29793// Get the containing RootView
794RootView* View::GetRootView() {
[email protected]a0dde122008-11-21 20:51:20795 Widget* widget = GetWidget();
796 return widget ? widget->GetRootView() : NULL;
initial.commit09911bf2008-07-26 23:55:29797}
798
799View* View::GetViewByID(int id) const {
800 if (id == id_)
801 return const_cast<View*>(this);
802
[email protected]09fe9492009-11-07 02:23:06803 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29804 View* child = GetChildViewAt(i);
805 View* view = child->GetViewByID(id);
806 if (view)
807 return view;
808 }
809 return NULL;
810}
811
812void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
813 if (group_ == group_id)
814 out->push_back(this);
815
[email protected]09fe9492009-11-07 02:23:06816 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29817 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
818}
819
820View* View::GetSelectedViewForGroup(int group_id) {
821 std::vector<View*> views;
822 GetRootView()->GetViewsWithGroup(group_id, &views);
823 if (views.size() > 0)
824 return views[0];
825 else
826 return NULL;
827}
828
829void View::SetID(int id) {
830 id_ = id;
831}
832
833int View::GetID() const {
834 return id_;
835}
836
837void View::SetGroup(int gid) {
[email protected]96f960d2009-09-14 18:45:30838 // Don't change the group id once it's set.
839 DCHECK(group_ == -1 || group_ == gid);
initial.commit09911bf2008-07-26 23:55:29840 group_ = gid;
841}
842
843int View::GetGroup() const {
844 return group_;
845}
846
847void View::SetParent(View* parent) {
[email protected]09fe9492009-11-07 02:23:06848 if (parent != parent_)
initial.commit09911bf2008-07-26 23:55:29849 parent_ = parent;
initial.commit09911bf2008-07-26 23:55:29850}
851
852bool View::IsParentOf(View* v) const {
853 DCHECK(v);
854 View* parent = v->GetParent();
855 while (parent) {
856 if (this == parent)
857 return true;
858 parent = parent->GetParent();
859 }
860 return false;
861}
862
[email protected]5e26d9d42010-05-13 22:11:03863int View::GetChildIndex(const View* v) const {
[email protected]09fe9492009-11-07 02:23:06864 for (int i = 0, count = GetChildViewCount(); i < count; i++) {
initial.commit09911bf2008-07-26 23:55:29865 if (v == GetChildViewAt(i))
866 return i;
867 }
868 return -1;
869}
870
871///////////////////////////////////////////////////////////////////////////////
872//
873// View - focus
874//
875///////////////////////////////////////////////////////////////////////////////
876
877View* View::GetNextFocusableView() {
878 return next_focusable_view_;
879}
880
881View* View::GetPreviousFocusableView() {
882 return previous_focusable_view_;
883}
884
885void View::SetNextFocusableView(View* view) {
886 view->previous_focusable_view_ = this;
887 next_focusable_view_ = view;
888}
889
890void View::InitFocusSiblings(View* v, int index) {
891 int child_count = static_cast<int>(child_views_.size());
892
893 if (child_count == 0) {
894 v->next_focusable_view_ = NULL;
895 v->previous_focusable_view_ = NULL;
896 } else {
897 if (index == child_count) {
898 // We are inserting at the end, but the end of the child list may not be
899 // the last focusable element. Let's try to find an element with no next
900 // focusable element to link to.
901 View* last_focusable_view = NULL;
902 for (std::vector<View*>::iterator iter = child_views_.begin();
903 iter != child_views_.end(); ++iter) {
904 if (!(*iter)->next_focusable_view_) {
905 last_focusable_view = *iter;
906 break;
907 }
908 }
909 if (last_focusable_view == NULL) {
910 // Hum... there is a cycle in the focus list. Let's just insert ourself
911 // after the last child.
912 View* prev = child_views_[index - 1];
913 v->previous_focusable_view_ = prev;
914 v->next_focusable_view_ = prev->next_focusable_view_;
915 prev->next_focusable_view_->previous_focusable_view_ = v;
916 prev->next_focusable_view_ = v;
917 } else {
918 last_focusable_view->next_focusable_view_ = v;
919 v->next_focusable_view_ = NULL;
920 v->previous_focusable_view_ = last_focusable_view;
921 }
922 } else {
923 View* prev = child_views_[index]->GetPreviousFocusableView();
924 v->previous_focusable_view_ = prev;
925 v->next_focusable_view_ = child_views_[index];
926 if (prev)
927 prev->next_focusable_view_ = v;
928 child_views_[index]->previous_focusable_view_ = v;
929 }
930 }
931}
932
933#ifndef NDEBUG
934void View::PrintViewHierarchy() {
935 PrintViewHierarchyImp(0);
936}
937
938void View::PrintViewHierarchyImp(int indent) {
939 std::wostringstream buf;
940 int ind = indent;
941 while (ind-- > 0)
942 buf << L' ';
943 buf << UTF8ToWide(GetClassName());
944 buf << L' ';
945 buf << GetID();
946 buf << L' ';
[email protected]80f8b9f2008-10-16 18:17:47947 buf << bounds_.x() << L"," << bounds_.y() << L",";
948 buf << bounds_.right() << L"," << bounds_.bottom();
initial.commit09911bf2008-07-26 23:55:29949 buf << L' ';
950 buf << this;
951
952 LOG(INFO) << buf.str();
953 std::cout << buf.str() << std::endl;
954
[email protected]09fe9492009-11-07 02:23:06955 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29956 GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
initial.commit09911bf2008-07-26 23:55:29957}
958
959
960void View::PrintFocusHierarchy() {
961 PrintFocusHierarchyImp(0);
962}
963
964void View::PrintFocusHierarchyImp(int indent) {
965 std::wostringstream buf;
966 int ind = indent;
967 while (ind-- > 0)
968 buf << L' ';
969 buf << UTF8ToWide(GetClassName());
970 buf << L' ';
971 buf << GetID();
972 buf << L' ';
973 buf << GetClassName().c_str();
974 buf << L' ';
975 buf << this;
976
977 LOG(INFO) << buf.str();
978 std::cout << buf.str() << std::endl;
979
980 if (GetChildViewCount() > 0)
981 GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
982
983 View* v = GetNextFocusableView();
984 if (v)
985 v->PrintFocusHierarchyImp(indent);
986}
987#endif
988
989////////////////////////////////////////////////////////////////////////////////
990//
991// View - accelerators
992//
993////////////////////////////////////////////////////////////////////////////////
994
995void View::AddAccelerator(const Accelerator& accelerator) {
996 if (!accelerators_.get())
997 accelerators_.reset(new std::vector<Accelerator>());
[email protected]71421c3f2009-06-06 00:41:44998
999 std::vector<Accelerator>::iterator iter =
1000 std::find(accelerators_->begin(), accelerators_->end(), accelerator);
1001 DCHECK(iter == accelerators_->end())
1002 << "Registering the same accelerator multiple times";
1003
initial.commit09911bf2008-07-26 23:55:291004 accelerators_->push_back(accelerator);
[email protected]71421c3f2009-06-06 00:41:441005 RegisterPendingAccelerators();
initial.commit09911bf2008-07-26 23:55:291006}
1007
[email protected]e8e0f362008-11-08 01:13:251008void View::RemoveAccelerator(const Accelerator& accelerator) {
1009 std::vector<Accelerator>::iterator iter;
1010 if (!accelerators_.get() ||
1011 ((iter = std::find(accelerators_->begin(), accelerators_->end(),
1012 accelerator)) == accelerators_->end())) {
1013 NOTREACHED() << "Removing non-existing accelerator";
1014 return;
1015 }
1016
[email protected]4bd23f32009-06-08 20:59:191017 size_t index = iter - accelerators_->begin();
[email protected]e8e0f362008-11-08 01:13:251018 accelerators_->erase(iter);
[email protected]71421c3f2009-06-06 00:41:441019 if (index >= registered_accelerator_count_) {
1020 // The accelerator is not registered to FocusManager.
1021 return;
1022 }
1023 --registered_accelerator_count_;
1024
[email protected]e8e0f362008-11-08 01:13:251025 RootView* root_view = GetRootView();
1026 if (!root_view) {
1027 // We are not part of a view hierarchy, so there is nothing to do as we
1028 // removed ourselves from accelerators_, we won't be registered when added
1029 // to one.
1030 return;
1031 }
1032
[email protected]bda9556c2010-01-07 00:55:161033 // If accelerator_focus_manager_ is NULL then we did not registered
1034 // accelerators so there is nothing to unregister.
1035 if (accelerator_focus_manager_) {
1036 accelerator_focus_manager_->UnregisterAccelerator(accelerator, this);
[email protected]e8e0f362008-11-08 01:13:251037 }
1038}
1039
initial.commit09911bf2008-07-26 23:55:291040void View::ResetAccelerators() {
[email protected]71421c3f2009-06-06 00:41:441041 if (accelerators_.get())
[email protected]bda9556c2010-01-07 00:55:161042 UnregisterAccelerators(false);
initial.commit09911bf2008-07-26 23:55:291043}
1044
[email protected]71421c3f2009-06-06 00:41:441045void View::RegisterPendingAccelerators() {
1046 if (!accelerators_.get() ||
1047 registered_accelerator_count_ == accelerators_->size()) {
1048 // No accelerators are waiting for registration.
initial.commit09911bf2008-07-26 23:55:291049 return;
[email protected]71421c3f2009-06-06 00:41:441050 }
initial.commit09911bf2008-07-26 23:55:291051
1052 RootView* root_view = GetRootView();
1053 if (!root_view) {
1054 // We are not yet part of a view hierarchy, we'll register ourselves once
1055 // added to one.
1056 return;
1057 }
[email protected]f3735c5d2009-03-19 17:26:231058
[email protected]bda9556c2010-01-07 00:55:161059 accelerator_focus_manager_ = GetFocusManager();
1060 if (!accelerator_focus_manager_) {
initial.commit09911bf2008-07-26 23:55:291061 // Some crash reports seem to show that we may get cases where we have no
1062 // focus manager (see bug #1291225). This should never be the case, just
1063 // making sure we don't crash.
[email protected]f8dce002009-09-10 21:07:041064
1065 // TODO(jcampan): This fails for a view under WidgetGtk with TYPE_CHILD.
1066 // (see http://crbug.com/21335) reenable NOTREACHED assertion and
1067 // verify accelerators works as expected.
1068#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:291069 NOTREACHED();
[email protected]f8dce002009-09-10 21:07:041070#endif
initial.commit09911bf2008-07-26 23:55:291071 return;
1072 }
[email protected]71421c3f2009-06-06 00:41:441073 std::vector<Accelerator>::const_iterator iter;
1074 for (iter = accelerators_->begin() + registered_accelerator_count_;
initial.commit09911bf2008-07-26 23:55:291075 iter != accelerators_->end(); ++iter) {
[email protected]bda9556c2010-01-07 00:55:161076 accelerator_focus_manager_->RegisterAccelerator(*iter, this);
initial.commit09911bf2008-07-26 23:55:291077 }
[email protected]71421c3f2009-06-06 00:41:441078 registered_accelerator_count_ = accelerators_->size();
initial.commit09911bf2008-07-26 23:55:291079}
1080
[email protected]bda9556c2010-01-07 00:55:161081void View::UnregisterAccelerators(bool leave_data_intact) {
initial.commit09911bf2008-07-26 23:55:291082 if (!accelerators_.get())
1083 return;
1084
1085 RootView* root_view = GetRootView();
1086 if (root_view) {
[email protected]bda9556c2010-01-07 00:55:161087 if (accelerator_focus_manager_) {
initial.commit09911bf2008-07-26 23:55:291088 // We may not have a FocusManager if the window containing us is being
1089 // closed, in which case the FocusManager is being deleted so there is
1090 // nothing to unregister.
[email protected]bda9556c2010-01-07 00:55:161091 accelerator_focus_manager_->UnregisterAccelerators(this);
1092 accelerator_focus_manager_ = NULL;
initial.commit09911bf2008-07-26 23:55:291093 }
[email protected]bda9556c2010-01-07 00:55:161094 if (!leave_data_intact) {
1095 accelerators_->clear();
1096 accelerators_.reset();
1097 }
[email protected]71421c3f2009-06-06 00:41:441098 registered_accelerator_count_ = 0;
initial.commit09911bf2008-07-26 23:55:291099 }
1100}
1101
[email protected]e9adf0702010-03-08 23:34:071102int View::GetDragOperations(const gfx::Point& press_pt) {
1103 return drag_controller_ ?
1104 drag_controller_->GetDragOperations(this, press_pt) :
1105 DragDropTypes::DRAG_NONE;
initial.commit09911bf2008-07-26 23:55:291106}
1107
[email protected]e9adf0702010-03-08 23:34:071108void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) {
initial.commit09911bf2008-07-26 23:55:291109 DCHECK(drag_controller_);
[email protected]e9adf0702010-03-08 23:34:071110 drag_controller_->WriteDragData(this, press_pt, data);
initial.commit09911bf2008-07-26 23:55:291111}
1112
1113void View::OnDragDone() {
1114}
1115
1116bool View::InDrag() {
1117 RootView* root_view = GetRootView();
1118 return root_view ? (root_view->GetDragView() == this) : false;
1119}
1120
[email protected]d5c81012010-04-03 00:56:121121bool View::GetAccessibleName(std::wstring* name) {
1122 DCHECK(name);
1123
1124 if (accessible_name_.empty())
1125 return false;
1126 *name = accessible_name_;
1127 return true;
1128}
1129
1130void View::SetAccessibleName(const std::wstring& name) {
1131 accessible_name_ = name;
1132}
1133
initial.commit09911bf2008-07-26 23:55:291134// static
[email protected]bb515ed2009-01-15 00:53:431135void View::ConvertPointToView(const View* src,
1136 const View* dst,
1137 gfx::Point* point) {
initial.commit09911bf2008-07-26 23:55:291138 ConvertPointToView(src, dst, point, true);
1139}
1140
1141// static
[email protected]bb515ed2009-01-15 00:53:431142void View::ConvertPointToView(const View* src,
1143 const View* dst,
1144 gfx::Point* point,
initial.commit09911bf2008-07-26 23:55:291145 bool try_other_direction) {
1146 // src can be NULL
1147 DCHECK(dst);
1148 DCHECK(point);
1149
[email protected]bb515ed2009-01-15 00:53:431150 const View* v;
initial.commit09911bf2008-07-26 23:55:291151 gfx::Point offset;
1152
1153 for (v = dst; v && v != src; v = v->GetParent()) {
1154 offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
[email protected]6f3bb6c2008-09-17 22:25:331155 offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291156 }
1157
1158 // The source was not found. The caller wants a conversion
1159 // from a view to a transitive parent.
1160 if (src && v == NULL && try_other_direction) {
1161 gfx::Point p;
1162 // note: try_other_direction is force to FALSE so we don't
1163 // end up in an infinite recursion should both src and dst
1164 // are not parented.
1165 ConvertPointToView(dst, src, &p, false);
1166 // since the src and dst are inverted, p should also be negated
1167 point->SetPoint(point->x() - p.x(), point->y() - p.y());
1168 } else {
1169 point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
1170
1171 // If src is NULL, sp is in the screen coordinate system
1172 if (src == NULL) {
[email protected]a0dde122008-11-21 20:51:201173 Widget* widget = dst->GetWidget();
1174 if (widget) {
[email protected]3b680a82008-12-17 02:03:231175 gfx::Rect b;
[email protected]a0dde122008-11-21 20:51:201176 widget->GetBounds(&b, false);
[email protected]3b680a82008-12-17 02:03:231177 point->SetPoint(point->x() - b.x(), point->y() - b.y());
initial.commit09911bf2008-07-26 23:55:291178 }
1179 }
1180 }
1181}
1182
1183// static
[email protected]2fb6d462009-02-13 18:40:101184void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291185 DCHECK(src);
1186 DCHECK(p);
[email protected]96b667d2008-10-14 20:58:441187
[email protected]96b667d2008-10-14 20:58:441188 gfx::Point offset;
[email protected]2fb6d462009-02-13 18:40:101189 for (const View* v = src; v; v = v->GetParent()) {
[email protected]96b667d2008-10-14 20:58:441190 offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION));
1191 offset.set_y(offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291192 }
[email protected]96b667d2008-10-14 20:58:441193 p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
initial.commit09911bf2008-07-26 23:55:291194}
1195
1196// static
[email protected]2fb6d462009-02-13 18:40:101197void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
[email protected]96b667d2008-10-14 20:58:441198 gfx::Point t;
[email protected]2fb6d462009-02-13 18:40:101199 ConvertPointToWidget(dest, &t);
[email protected]96b667d2008-10-14 20:58:441200 p->SetPoint(p->x() - t.x(), p->y() - t.y());
initial.commit09911bf2008-07-26 23:55:291201}
1202
1203// static
[email protected]2fb6d462009-02-13 18:40:101204void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291205 DCHECK(src);
1206 DCHECK(p);
1207
[email protected]96b667d2008-10-14 20:58:441208 // If the view is not connected to a tree, there's nothing we can do.
[email protected]a0dde122008-11-21 20:51:201209 Widget* widget = src->GetWidget();
1210 if (widget) {
1211 ConvertPointToWidget(src, p);
[email protected]3b680a82008-12-17 02:03:231212 gfx::Rect r;
[email protected]a0dde122008-11-21 20:51:201213 widget->GetBounds(&r, false);
[email protected]3b680a82008-12-17 02:03:231214 p->SetPoint(p->x() + r.x(), p->y() + r.y());
initial.commit09911bf2008-07-26 23:55:291215 }
1216}
1217
1218/////////////////////////////////////////////////////////////////////////////
1219//
1220// View - event handlers
1221//
1222/////////////////////////////////////////////////////////////////////////////
1223
1224bool View::OnMousePressed(const MouseEvent& e) {
1225 return false;
1226}
1227
1228bool View::OnMouseDragged(const MouseEvent& e) {
1229 return false;
1230}
1231
1232void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
1233}
1234
1235void View::OnMouseMoved(const MouseEvent& e) {
1236}
1237
1238void View::OnMouseEntered(const MouseEvent& e) {
1239}
1240
1241void View::OnMouseExited(const MouseEvent& e) {
1242}
1243
1244void View::SetMouseHandler(View *new_mouse_handler) {
1245 // It is valid for new_mouse_handler to be NULL
[email protected]09fe9492009-11-07 02:23:061246 if (parent_)
initial.commit09911bf2008-07-26 23:55:291247 parent_->SetMouseHandler(new_mouse_handler);
initial.commit09911bf2008-07-26 23:55:291248}
1249
1250void View::SetVisible(bool flag) {
1251 if (flag != is_visible_) {
1252 // If the tab is currently visible, schedule paint to
1253 // refresh parent
[email protected]09fe9492009-11-07 02:23:061254 if (IsVisible())
initial.commit09911bf2008-07-26 23:55:291255 SchedulePaint();
initial.commit09911bf2008-07-26 23:55:291256
1257 is_visible_ = flag;
1258
1259 // This notifies all subviews recursively.
1260 PropagateVisibilityNotifications(this, flag);
1261
1262 // If we are newly visible, schedule paint.
[email protected]09fe9492009-11-07 02:23:061263 if (IsVisible())
initial.commit09911bf2008-07-26 23:55:291264 SchedulePaint();
initial.commit09911bf2008-07-26 23:55:291265 }
1266}
1267
1268bool View::IsVisibleInRootView() const {
1269 View* parent = GetParent();
1270 if (IsVisible() && parent)
1271 return parent->IsVisibleInRootView();
1272 else
1273 return false;
1274}
1275
initial.commit09911bf2008-07-26 23:55:291276/////////////////////////////////////////////////////////////////////////////
1277//
1278// View - keyboard and focus
1279//
1280/////////////////////////////////////////////////////////////////////////////
1281
1282void View::RequestFocus() {
1283 RootView* rv = GetRootView();
[email protected]830e2062009-02-13 18:27:381284 if (rv && IsFocusable())
initial.commit09911bf2008-07-26 23:55:291285 rv->FocusView(this);
initial.commit09911bf2008-07-26 23:55:291286}
1287
1288void View::WillGainFocus() {
1289}
1290
1291void View::DidGainFocus() {
1292}
1293
1294void View::WillLoseFocus() {
1295}
1296
1297bool View::OnKeyPressed(const KeyEvent& e) {
1298 return false;
1299}
1300
1301bool View::OnKeyReleased(const KeyEvent& e) {
1302 return false;
1303}
1304
1305bool View::OnMouseWheel(const MouseWheelEvent& e) {
1306 return false;
1307}
1308
1309void View::SetDragController(DragController* drag_controller) {
[email protected]09fe9492009-11-07 02:23:061310 drag_controller_ = drag_controller;
initial.commit09911bf2008-07-26 23:55:291311}
1312
1313DragController* View::GetDragController() {
1314 return drag_controller_;
1315}
1316
[email protected]134c47b92009-08-19 03:33:441317bool View::GetDropFormats(
1318 int* formats,
1319 std::set<OSExchangeData::CustomFormat>* custom_formats) {
1320 return false;
1321}
1322
1323bool View::AreDropTypesRequired() {
1324 return false;
1325}
1326
initial.commit09911bf2008-07-26 23:55:291327bool View::CanDrop(const OSExchangeData& data) {
[email protected]134c47b92009-08-19 03:33:441328 // TODO(sky): when I finish up migration, this should default to true.
initial.commit09911bf2008-07-26 23:55:291329 return false;
1330}
1331
1332void View::OnDragEntered(const DropTargetEvent& event) {
1333}
1334
1335int View::OnDragUpdated(const DropTargetEvent& event) {
1336 return DragDropTypes::DRAG_NONE;
1337}
1338
1339void View::OnDragExited() {
1340}
1341
1342int View::OnPerformDrop(const DropTargetEvent& event) {
1343 return DragDropTypes::DRAG_NONE;
1344}
1345
initial.commit09911bf2008-07-26 23:55:291346// static
1347bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1348 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1349 abs(delta_y) > GetVerticalDragThreshold());
1350}
1351
initial.commit09911bf2008-07-26 23:55:291352// Tooltips -----------------------------------------------------------------
[email protected]e9adf0702010-03-08 23:34:071353bool View::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
initial.commit09911bf2008-07-26 23:55:291354 return false;
1355}
1356
[email protected]e9adf0702010-03-08 23:34:071357bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) {
initial.commit09911bf2008-07-26 23:55:291358 return false;
1359}
1360
1361void View::TooltipTextChanged() {
[email protected]a0dde122008-11-21 20:51:201362 Widget* widget = GetWidget();
1363 if (widget && widget->GetTooltipManager())
1364 widget->GetTooltipManager()->TooltipTextChanged(this);
initial.commit09911bf2008-07-26 23:55:291365}
1366
1367void View::UpdateTooltip() {
[email protected]a0dde122008-11-21 20:51:201368 Widget* widget = GetWidget();
1369 if (widget && widget->GetTooltipManager())
1370 widget->GetTooltipManager()->UpdateTooltip();
initial.commit09911bf2008-07-26 23:55:291371}
1372
initial.commit09911bf2008-07-26 23:55:291373std::string View::GetClassName() const {
1374 return kViewClassName;
1375}
1376
[email protected]5c2b98b2009-03-09 20:55:541377View* View::GetAncestorWithClassName(const std::string& name) {
1378 for (View* view = this; view; view = view->GetParent()) {
1379 if (view->GetClassName() == name)
1380 return view;
1381 }
1382 return NULL;
1383}
1384
initial.commit09911bf2008-07-26 23:55:291385gfx::Rect View::GetVisibleBounds() {
[email protected]b6296fd2009-02-13 17:34:161386 if (!IsVisibleInRootView())
1387 return gfx::Rect();
[email protected]6f3bb6c2008-09-17 22:25:331388 gfx::Rect vis_bounds(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:291389 gfx::Rect ancestor_bounds;
1390 View* view = this;
1391 int root_x = 0;
1392 int root_y = 0;
initial.commit09911bf2008-07-26 23:55:291393 while (view != NULL && !vis_bounds.IsEmpty()) {
1394 root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
[email protected]6f3bb6c2008-09-17 22:25:331395 root_y += view->y();
1396 vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y());
initial.commit09911bf2008-07-26 23:55:291397 View* ancestor = view->GetParent();
1398 if (ancestor != NULL) {
[email protected]6f3bb6c2008-09-17 22:25:331399 ancestor_bounds.SetRect(0, 0, ancestor->width(),
1400 ancestor->height());
initial.commit09911bf2008-07-26 23:55:291401 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
[email protected]a0dde122008-11-21 20:51:201402 } else if (!view->GetWidget()) {
1403 // If the view has no Widget, we're not visible. Return an empty rect.
initial.commit09911bf2008-07-26 23:55:291404 return gfx::Rect();
1405 }
1406 view = ancestor;
1407 }
1408 if (vis_bounds.IsEmpty())
1409 return vis_bounds;
1410 // Convert back to this views coordinate system.
1411 vis_bounds.Offset(-root_x, -root_y);
1412 return vis_bounds;
1413}
1414
1415int View::GetPageScrollIncrement(ScrollView* scroll_view,
1416 bool is_horizontal, bool is_positive) {
1417 return 0;
1418}
1419
1420int View::GetLineScrollIncrement(ScrollView* scroll_view,
1421 bool is_horizontal, bool is_positive) {
1422 return 0;
1423}
1424
[email protected]45da6c72009-10-28 20:45:421425ThemeProvider* View::GetThemeProvider() const {
[email protected]4a190632009-05-09 01:07:421426 Widget* widget = GetWidget();
1427 return widget ? widget->GetThemeProvider() : NULL;
1428}
1429
initial.commit09911bf2008-07-26 23:55:291430// static
1431void View::RegisterChildrenForVisibleBoundsNotification(
1432 RootView* root, View* view) {
1433 DCHECK(root && view);
1434 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1435 root->RegisterViewForVisibleBoundsNotification(view);
1436 for (int i = 0; i < view->GetChildViewCount(); ++i)
1437 RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i));
1438}
1439
1440// static
1441void View::UnregisterChildrenForVisibleBoundsNotification(
1442 RootView* root, View* view) {
1443 DCHECK(root && view);
1444 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1445 root->UnregisterViewForVisibleBoundsNotification(view);
1446 for (int i = 0; i < view->GetChildViewCount(); ++i)
1447 UnregisterChildrenForVisibleBoundsNotification(root,
1448 view->GetChildViewAt(i));
1449}
1450
1451void View::AddDescendantToNotify(View* view) {
1452 DCHECK(view);
1453 if (!descendants_to_notify_.get())
1454 descendants_to_notify_.reset(new ViewList());
1455 descendants_to_notify_->push_back(view);
1456}
1457
1458void View::RemoveDescendantToNotify(View* view) {
1459 DCHECK(view && descendants_to_notify_.get());
1460 ViewList::iterator i = find(descendants_to_notify_->begin(),
1461 descendants_to_notify_->end(),
1462 view);
1463 DCHECK(i != descendants_to_notify_->end());
1464 descendants_to_notify_->erase(i);
1465 if (descendants_to_notify_->empty())
1466 descendants_to_notify_.reset();
1467}
1468
initial.commit09911bf2008-07-26 23:55:291469// DropInfo --------------------------------------------------------------------
1470
1471void View::DragInfo::Reset() {
1472 possible_drag = false;
[email protected]e9adf0702010-03-08 23:34:071473 start_pt = gfx::Point();
initial.commit09911bf2008-07-26 23:55:291474}
1475
[email protected]e9adf0702010-03-08 23:34:071476void View::DragInfo::PossibleDrag(const gfx::Point& p) {
initial.commit09911bf2008-07-26 23:55:291477 possible_drag = true;
[email protected]e9adf0702010-03-08 23:34:071478 start_pt = p;
initial.commit09911bf2008-07-26 23:55:291479}
1480
1481} // namespace