blob: d8ba4c3c89a8535462defd1e5c92dcc23c980aa9 [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]83548a42010-06-18 13:53:3757 accessibility_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),
initial.commit09911bf2008-07-26 23:55:2974 flip_canvas_on_paint_for_rtl_ui_(false) {
75}
76
77View::~View() {
[email protected]8c57de22010-03-12 21:06:0478 if (parent_)
79 parent_->RemoveChildView(this);
80
initial.commit09911bf2008-07-26 23:55:2981 int c = static_cast<int>(child_views_.size());
82 while (--c >= 0) {
[email protected]8c57de22010-03-12 21:06:0483 child_views_[c]->SetParent(NULL);
initial.commit09911bf2008-07-26 23:55:2984 if (child_views_[c]->IsParentOwned())
85 delete child_views_[c];
initial.commit09911bf2008-07-26 23:55:2986 }
[email protected]a64f33902009-10-10 05:41:2387
88#if defined(OS_WIN)
[email protected]09fe9492009-11-07 02:23:0689 if (accessibility_.get())
[email protected]a64f33902009-10-10 05:41:2390 accessibility_->Uninitialize();
[email protected]a64f33902009-10-10 05:41:2391#endif
initial.commit09911bf2008-07-26 23:55:2992}
93
94/////////////////////////////////////////////////////////////////////////////
95//
96// View - sizing
97//
98/////////////////////////////////////////////////////////////////////////////
99
[email protected]0d8ea702008-10-14 17:03:07100gfx::Rect View::GetBounds(PositionMirroringSettings settings) const {
101 gfx::Rect bounds(bounds_);
initial.commit09911bf2008-07-26 23:55:29102
103 // If the parent uses an RTL UI layout and if we are asked to transform the
104 // bounds to their mirrored position if necessary, then we should shift the
105 // rectangle appropriately.
[email protected]0d8ea702008-10-14 17:03:07106 if (settings == APPLY_MIRRORING_TRANSFORMATION)
107 bounds.set_x(MirroredX());
[email protected]4f3dc372009-02-24 00:10:29108
[email protected]0d8ea702008-10-14 17:03:07109 return bounds;
initial.commit09911bf2008-07-26 23:55:29110}
111
[email protected]6f3bb6c2008-09-17 22:25:33112// y(), width() and height() are agnostic to the RTL UI layout of the
113// parent view. x(), on the other hand, is not.
initial.commit09911bf2008-07-26 23:55:29114int View::GetX(PositionMirroringSettings settings) const {
[email protected]80f8b9f2008-10-16 18:17:47115 return settings == IGNORE_MIRRORING_TRANSFORMATION ? x() : MirroredX();
initial.commit09911bf2008-07-26 23:55:29116}
117
[email protected]80f8b9f2008-10-16 18:17:47118void View::SetBounds(const gfx::Rect& bounds) {
119 if (bounds == bounds_)
initial.commit09911bf2008-07-26 23:55:29120 return;
initial.commit09911bf2008-07-26 23:55:29121
[email protected]80f8b9f2008-10-16 18:17:47122 gfx::Rect prev = bounds_;
initial.commit09911bf2008-07-26 23:55:29123 bounds_ = bounds;
[email protected]b97c8a22010-02-05 19:36:43124 bool size_changed = prev.size() != bounds_.size();
125 bool position_changed = prev.origin() != bounds_.origin();
initial.commit09911bf2008-07-26 23:55:29126
[email protected]b97c8a22010-02-05 19:36:43127 if (size_changed || position_changed) {
128 DidChangeBounds(prev, bounds_);
129
130 RootView* root = GetRootView();
131 if (root)
initial.commit09911bf2008-07-26 23:55:29132 root->ViewBoundsChanged(this, size_changed, position_changed);
133 }
134}
135
[email protected]7e7c82a2010-06-15 20:10:16136void View::RegisterForMouseNearEvents(const gfx::Insets& insets) {
137 RootView* root = GetRootView();
138 if (insets.empty()) {
139 near_insets_.reset(NULL);
140 if (root)
141 root->UnregisterViewForNearNotification(this);
142 } else {
143 near_insets_.reset(
144 new gfx::Insets(insets.top(), insets.left(), insets.bottom(),
145 insets.right()));
146 if (root)
147 root->RegisterViewForNearNotification(this);
148 }
149}
150
[email protected]80f8b9f2008-10-16 18:17:47151gfx::Rect View::GetLocalBounds(bool include_border) const {
[email protected]9a3f0ac22008-11-14 03:24:02152 if (include_border || !border_.get())
[email protected]80f8b9f2008-10-16 18:17:47153 return gfx::Rect(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:29154
[email protected]80f8b9f2008-10-16 18:17:47155 gfx::Insets insets;
156 border_->GetInsets(&insets);
157 return gfx::Rect(insets.left(), insets.top(),
[email protected]4a8d3272009-03-10 19:15:08158 std::max(0, width() - insets.width()),
159 std::max(0, height() - insets.height()));
initial.commit09911bf2008-07-26 23:55:29160}
161
[email protected]0a1d36b22008-10-17 19:33:09162gfx::Point View::GetPosition() const {
163 return gfx::Point(GetX(APPLY_MIRRORING_TRANSFORMATION), y());
initial.commit09911bf2008-07-26 23:55:29164}
165
[email protected]154f8bc2008-10-15 18:02:30166gfx::Size View::GetPreferredSize() {
167 if (layout_manager_.get())
168 return layout_manager_->GetPreferredSize(this);
169 return gfx::Size();
initial.commit09911bf2008-07-26 23:55:29170}
171
[email protected]a1360162009-11-30 21:19:07172int View::GetBaseline() {
173 return -1;
174}
175
initial.commit09911bf2008-07-26 23:55:29176void View::SizeToPreferredSize() {
[email protected]154f8bc2008-10-15 18:02:30177 gfx::Size prefsize = GetPreferredSize();
178 if ((prefsize.width() != width()) || (prefsize.height() != height()))
179 SetBounds(x(), y(), prefsize.width(), prefsize.height());
initial.commit09911bf2008-07-26 23:55:29180}
181
[email protected]7ccc52b72009-05-08 21:09:11182void View::PreferredSizeChanged() {
183 if (parent_)
184 parent_->ChildPreferredSizeChanged(this);
185}
186
[email protected]154f8bc2008-10-15 18:02:30187gfx::Size View::GetMinimumSize() {
188 return GetPreferredSize();
initial.commit09911bf2008-07-26 23:55:29189}
190
191int View::GetHeightForWidth(int w) {
192 if (layout_manager_.get())
193 return layout_manager_->GetPreferredHeightForWidth(this, w);
[email protected]154f8bc2008-10-15 18:02:30194 return GetPreferredSize().height();
initial.commit09911bf2008-07-26 23:55:29195}
196
[email protected]80f8b9f2008-10-16 18:17:47197void View::DidChangeBounds(const gfx::Rect& previous,
198 const gfx::Rect& current) {
199 Layout();
initial.commit09911bf2008-07-26 23:55:29200}
201
[email protected]e9adf0702010-03-08 23:34:07202void View::ScrollRectToVisible(const gfx::Rect& rect) {
initial.commit09911bf2008-07-26 23:55:29203 View* parent = GetParent();
204
205 // We must take RTL UI mirroring into account when adjusting the position of
206 // the region.
[email protected]e9adf0702010-03-08 23:34:07207 if (parent) {
208 gfx::Rect scroll_rect(rect);
209 scroll_rect.Offset(GetX(APPLY_MIRRORING_TRANSFORMATION), y());
210 parent->ScrollRectToVisible(scroll_rect);
211 }
initial.commit09911bf2008-07-26 23:55:29212}
213
214/////////////////////////////////////////////////////////////////////////////
215//
216// View - layout
217//
218/////////////////////////////////////////////////////////////////////////////
219
220void View::Layout() {
221 // Layout child Views
222 if (layout_manager_.get()) {
223 layout_manager_->Layout(this);
224 SchedulePaint();
[email protected]d5c4f382009-02-24 21:47:36225 // TODO(beng): We believe the right thing to do here is return since the
226 // layout manager should be handling things, but it causes
227 // regressions (missing options from Options dialog and a hang
228 // in interactive_ui_tests).
initial.commit09911bf2008-07-26 23:55:29229 }
230
231 // Lay out contents of child Views
[email protected]09fe9492009-11-07 02:23:06232 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29233 View* child = GetChildViewAt(i);
234 child->Layout();
235 }
236}
237
238LayoutManager* View::GetLayoutManager() const {
239 return layout_manager_.get();
240}
241
242void View::SetLayoutManager(LayoutManager* layout_manager) {
[email protected]09fe9492009-11-07 02:23:06243 if (layout_manager_.get())
initial.commit09911bf2008-07-26 23:55:29244 layout_manager_->Uninstalled(this);
[email protected]09fe9492009-11-07 02:23:06245
initial.commit09911bf2008-07-26 23:55:29246 layout_manager_.reset(layout_manager);
[email protected]09fe9492009-11-07 02:23:06247 if (layout_manager_.get())
initial.commit09911bf2008-07-26 23:55:29248 layout_manager_->Installed(this);
initial.commit09911bf2008-07-26 23:55:29249}
250
251////////////////////////////////////////////////////////////////////////////////
252//
253// View - Right-to-left UI layout
254//
255////////////////////////////////////////////////////////////////////////////////
256
[email protected]c3bca422010-02-19 23:29:02257int View::MirroredX() const {
initial.commit09911bf2008-07-26 23:55:29258 View* parent = GetParent();
[email protected]aaa71da52010-02-19 21:39:24259 return parent ? parent->MirroredLeftPointForRect(bounds_) : x();
initial.commit09911bf2008-07-26 23:55:29260}
261
262int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const {
[email protected]c2f4bdb72010-05-10 23:15:21263 return base::i18n::IsRTL() ?
[email protected]aaa71da52010-02-19 21:39:24264 (width() - bounds.x() - bounds.width()) : bounds.x();
initial.commit09911bf2008-07-26 23:55:29265}
266
267////////////////////////////////////////////////////////////////////////////////
268//
269// View - states
270//
271////////////////////////////////////////////////////////////////////////////////
272
273bool View::IsEnabled() const {
274 return enabled_;
275}
276
277void View::SetEnabled(bool state) {
278 if (enabled_ != state) {
279 enabled_ = state;
280 SchedulePaint();
281 }
282}
283
284bool View::IsFocusable() const {
[email protected]83548a42010-06-18 13:53:37285 return focusable_ && IsEnabled() && IsVisible();
initial.commit09911bf2008-07-26 23:55:29286}
287
288void View::SetFocusable(bool focusable) {
289 focusable_ = focusable;
290}
291
[email protected]83548a42010-06-18 13:53:37292bool View::IsAccessibilityFocusable() const {
293 return (focusable_ || accessibility_focusable_) && IsEnabled() && IsVisible();
294}
295
[email protected]82166b62009-06-30 18:48:00296FocusManager* View::GetFocusManager() {
297 Widget* widget = GetWidget();
298 return widget ? widget->GetFocusManager() : NULL;
299}
300
initial.commit09911bf2008-07-26 23:55:29301bool View::HasFocus() {
initial.commit09911bf2008-07-26 23:55:29302 FocusManager* focus_manager = GetFocusManager();
303 if (focus_manager)
304 return focus_manager->GetFocusedView() == this;
305 return false;
306}
307
[email protected]5c9e97a2009-09-09 23:48:30308void View::Focus() {
[email protected]7f14e1f2009-10-01 15:57:26309 // By default, we clear the native focus. This ensures that no visible native
310 // view as the focus and that we still receive keyboard inputs.
[email protected]5c9e97a2009-09-09 23:48:30311 FocusManager* focus_manager = GetFocusManager();
312 if (focus_manager)
[email protected]7f14e1f2009-10-01 15:57:26313 focus_manager->ClearNativeFocus();
[email protected]5c9e97a2009-09-09 23:48:30314}
315
initial.commit09911bf2008-07-26 23:55:29316void View::SetHotTracked(bool flag) {
317}
318
319/////////////////////////////////////////////////////////////////////////////
320//
321// View - painting
322//
323/////////////////////////////////////////////////////////////////////////////
324
[email protected]0a1d36b22008-10-17 19:33:09325void View::SchedulePaint(const gfx::Rect& r, bool urgent) {
326 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29327 return;
initial.commit09911bf2008-07-26 23:55:29328
329 if (parent_) {
330 // Translate the requested paint rect to the parent's coordinate system
331 // then pass this notification up to the parent.
[email protected]0a1d36b22008-10-17 19:33:09332 gfx::Rect paint_rect = r;
333 paint_rect.Offset(GetPosition());
initial.commit09911bf2008-07-26 23:55:29334 parent_->SchedulePaint(paint_rect, urgent);
335 }
336}
337
338void View::SchedulePaint() {
[email protected]0a1d36b22008-10-17 19:33:09339 SchedulePaint(GetLocalBounds(true), false);
initial.commit09911bf2008-07-26 23:55:29340}
341
[email protected]82522512009-05-15 07:37:29342void View::Paint(gfx::Canvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29343 PaintBackground(canvas);
344 PaintFocusBorder(canvas);
345 PaintBorder(canvas);
346}
347
[email protected]82522512009-05-15 07:37:29348void View::PaintBackground(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02349 if (background_.get())
initial.commit09911bf2008-07-26 23:55:29350 background_->Paint(canvas, this);
351}
352
[email protected]82522512009-05-15 07:37:29353void View::PaintBorder(gfx::Canvas* canvas) {
[email protected]9a3f0ac22008-11-14 03:24:02354 if (border_.get())
initial.commit09911bf2008-07-26 23:55:29355 border_->Paint(*this, canvas);
356}
357
[email protected]82522512009-05-15 07:37:29358void View::PaintFocusBorder(gfx::Canvas* canvas) {
[email protected]83548a42010-06-18 13:53:37359 if (HasFocus() && (IsFocusable() ||
360 IsAccessibilityFocusable())) {
[email protected]6f3bb6c2008-09-17 22:25:33361 canvas->DrawFocusRect(0, 0, width(), height());
[email protected]83548a42010-06-18 13:53:37362 }
initial.commit09911bf2008-07-26 23:55:29363}
364
[email protected]82522512009-05-15 07:37:29365void View::PaintChildren(gfx::Canvas* canvas) {
[email protected]09fe9492009-11-07 02:23:06366 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29367 View* child = GetChildViewAt(i);
368 if (!child) {
369 NOTREACHED() << "Should not have a NULL child View for index in bounds";
370 continue;
371 }
372 child->ProcessPaint(canvas);
373 }
374}
375
[email protected]82522512009-05-15 07:37:29376void View::ProcessPaint(gfx::Canvas* canvas) {
[email protected]09fe9492009-11-07 02:23:06377 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29378 return;
initial.commit09911bf2008-07-26 23:55:29379
380 // We're going to modify the canvas, save it's state first.
381 canvas->save();
382
383 // Paint this View and its children, setting the clip rect to the bounds
384 // of this View and translating the origin to the local bounds' top left
385 // point.
386 //
387 // Note that the X (or left) position we pass to ClipRectInt takes into
388 // consideration whether or not the view uses a right-to-left layout so that
389 // we paint our view in its mirrored position if need be.
[email protected]80f8b9f2008-10-16 18:17:47390 if (canvas->ClipRectInt(MirroredX(), y(), width(), height())) {
initial.commit09911bf2008-07-26 23:55:29391 // Non-empty clip, translate the graphics such that 0,0 corresponds to
392 // where this view is located (related to its parent).
[email protected]80f8b9f2008-10-16 18:17:47393 canvas->TranslateInt(MirroredX(), y());
initial.commit09911bf2008-07-26 23:55:29394
395 // Save the state again, so that any changes don't effect PaintChildren.
396 canvas->save();
397
398 // If the View we are about to paint requested the canvas to be flipped, we
399 // should change the transform appropriately.
400 bool flip_canvas = FlipCanvasOnPaintForRTLUI();
401 if (flip_canvas) {
[email protected]6f3bb6c2008-09-17 22:25:33402 canvas->TranslateInt(width(), 0);
initial.commit09911bf2008-07-26 23:55:29403 canvas->ScaleInt(-1, 1);
404 canvas->save();
405 }
406
407 Paint(canvas);
408
409 // We must undo the canvas mirroring once the View is done painting so that
410 // we don't pass the canvas with the mirrored transform to Views that
411 // didn't request the canvas to be flipped.
[email protected]09fe9492009-11-07 02:23:06412 if (flip_canvas)
initial.commit09911bf2008-07-26 23:55:29413 canvas->restore();
[email protected]09fe9492009-11-07 02:23:06414
initial.commit09911bf2008-07-26 23:55:29415 canvas->restore();
416 PaintChildren(canvas);
417 }
418
419 // Restore the canvas's original transform.
420 canvas->restore();
421}
422
423void View::PaintNow() {
[email protected]09fe9492009-11-07 02:23:06424 if (!IsVisible())
initial.commit09911bf2008-07-26 23:55:29425 return;
initial.commit09911bf2008-07-26 23:55:29426
427 View* view = GetParent();
428 if (view)
429 view->PaintNow();
430}
431
initial.commit09911bf2008-07-26 23:55:29432gfx::Insets View::GetInsets() const {
initial.commit09911bf2008-07-26 23:55:29433 gfx::Insets insets;
[email protected]9a3f0ac22008-11-14 03:24:02434 if (border_.get())
435 border_->GetInsets(&insets);
initial.commit09911bf2008-07-26 23:55:29436 return insets;
437}
438
[email protected]e9adf0702010-03-08 23:34:07439gfx::NativeCursor View::GetCursorForPoint(Event::EventType event_type,
440 const gfx::Point& p) {
[email protected]9abf8dd62009-06-04 06:40:42441 return NULL;
442}
443
[email protected]a52ca4672009-06-05 05:41:09444bool View::HitTest(const gfx::Point& l) const {
[email protected]d7fc97942009-11-20 22:07:11445 if (l.x() >= 0 && l.x() < width() && l.y() >= 0 && l.y() < height()) {
[email protected]a52ca4672009-06-05 05:41:09446 if (HasHitTestMask()) {
447 gfx::Path mask;
448 GetHitTestMask(&mask);
[email protected]a3406972009-11-04 05:05:48449 ScopedRegion rgn(mask.CreateNativeRegion());
450 // TODO: can this use SkRegion's contains instead?
[email protected]a52ca4672009-06-05 05:41:09451#if defined(OS_WIN)
[email protected]a52ca4672009-06-05 05:41:09452 return !!PtInRegion(rgn, l.x(), l.y());
[email protected]10a6e77b2009-12-31 01:03:52453#elif defined(TOOLKIT_USES_GTK)
[email protected]a3406972009-11-04 05:05:48454 return gdk_region_point_in(rgn.Get(), l.x(), l.y());
[email protected]a52ca4672009-06-05 05:41:09455#endif
456 }
457 // No mask, but inside our bounds.
458 return true;
459 }
460 // Outside our bounds.
461 return false;
462}
463
initial.commit09911bf2008-07-26 23:55:29464void View::SetContextMenuController(ContextMenuController* menu_controller) {
465 context_menu_controller_ = menu_controller;
466}
467
[email protected]e9adf0702010-03-08 23:34:07468void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) {
[email protected]042811c2008-10-31 21:31:34469 if (!context_menu_controller_)
470 return;
471
[email protected]e9adf0702010-03-08 23:34:07472 context_menu_controller_->ShowContextMenu(this, p, is_mouse_gesture);
[email protected]042811c2008-10-31 21:31:34473}
474
initial.commit09911bf2008-07-26 23:55:29475/////////////////////////////////////////////////////////////////////////////
476//
477// View - tree
478//
479/////////////////////////////////////////////////////////////////////////////
480
481bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
[email protected]83548a42010-06-18 13:53:37482 const bool enabled = IsEnabled();
[email protected]e9adf0702010-03-08 23:34:07483 int drag_operations =
484 (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location())) ?
485 GetDragOperations(e.location()) : 0;
486 ContextMenuController* context_menu_controller = e.IsRightMouseButton() ?
487 context_menu_controller_ : 0;
initial.commit09911bf2008-07-26 23:55:29488
489 const bool result = OnMousePressed(e);
490 // WARNING: we may have been deleted, don't use any View variables;
491
492 if (!enabled)
493 return result;
494
495 if (drag_operations != DragDropTypes::DRAG_NONE) {
[email protected]e9adf0702010-03-08 23:34:07496 drag_info->PossibleDrag(e.location());
initial.commit09911bf2008-07-26 23:55:29497 return true;
498 }
499 return !!context_menu_controller || result;
500}
501
502bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
503 // Copy the field, that way if we're deleted after drag and drop no harm is
504 // done.
505 ContextMenuController* context_menu_controller = context_menu_controller_;
506 const bool possible_drag = drag_info->possible_drag;
[email protected]e9adf0702010-03-08 23:34:07507 if (possible_drag && ExceededDragThreshold(drag_info->start_pt.x() - e.x(),
508 drag_info->start_pt.y() - e.y())) {
[email protected]b5f94de2009-12-04 07:59:00509 if (!drag_controller_ ||
[email protected]e9adf0702010-03-08 23:34:07510 drag_controller_->CanStartDrag(this, drag_info->start_pt, e.location()))
511 DoDrag(e, drag_info->start_pt);
initial.commit09911bf2008-07-26 23:55:29512 } else {
513 if (OnMouseDragged(e))
514 return true;
515 // Fall through to return value based on context menu controller.
516 }
517 // WARNING: we may have been deleted.
518 return (context_menu_controller != NULL) || possible_drag;
519}
520
521void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
522 if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
523 // Assume that if there is a context menu controller we won't be deleted
524 // from mouse released.
[email protected]96b667d2008-10-14 20:58:44525 gfx::Point location(e.location());
initial.commit09911bf2008-07-26 23:55:29526 OnMouseReleased(e, canceled);
[email protected]464fdb32009-03-19 20:25:44527 if (HitTest(location)) {
528 ConvertPointToScreen(this, &location);
[email protected]e9adf0702010-03-08 23:34:07529 ShowContextMenu(location, true);
[email protected]464fdb32009-03-19 20:25:44530 }
initial.commit09911bf2008-07-26 23:55:29531 } else {
532 OnMouseReleased(e, canceled);
533 }
534 // WARNING: we may have been deleted.
535}
536
initial.commit09911bf2008-07-26 23:55:29537void View::AddChildView(View* v) {
[email protected]0d52b2302009-05-11 23:50:55538 AddChildView(static_cast<int>(child_views_.size()), v);
initial.commit09911bf2008-07-26 23:55:29539}
540
541void View::AddChildView(int index, View* v) {
[email protected]0b2fa2b2009-12-01 01:06:12542 CHECK(v != this) << "You cannot add a view as its own child";
543
initial.commit09911bf2008-07-26 23:55:29544 // Remove the view from its current parent if any.
545 if (v->GetParent())
546 v->GetParent()->RemoveChildView(v);
547
[email protected]0d52b2302009-05-11 23:50:55548 // Sets the prev/next focus views.
549 InitFocusSiblings(v, index);
initial.commit09911bf2008-07-26 23:55:29550
551 // Let's insert the view.
552 child_views_.insert(child_views_.begin() + index, v);
553 v->SetParent(this);
554
[email protected]09fe9492009-11-07 02:23:06555 for (View* p = this; p; p = p->GetParent())
initial.commit09911bf2008-07-26 23:55:29556 p->ViewHierarchyChangedImpl(false, true, this, v);
[email protected]09fe9492009-11-07 02:23:06557
initial.commit09911bf2008-07-26 23:55:29558 v->PropagateAddNotifications(this, v);
559 UpdateTooltip();
560 RootView* root = GetRootView();
561 if (root)
[email protected]7e7c82a2010-06-15 20:10:16562 RegisterChildrenForRootNotifications(root, v);
initial.commit09911bf2008-07-26 23:55:29563
564 if (layout_manager_.get())
565 layout_manager_->ViewAdded(this, v);
566}
567
568View* View::GetChildViewAt(int index) const {
569 return index < GetChildViewCount() ? child_views_[index] : NULL;
570}
571
572int View::GetChildViewCount() const {
573 return static_cast<int>(child_views_.size());
574}
575
[email protected]3a9c26f2010-03-12 21:04:39576bool View::HasChildView(View* a_view) {
577 return find(child_views_.begin(),
578 child_views_.end(),
579 a_view) != child_views_.end();
580}
581
initial.commit09911bf2008-07-26 23:55:29582void View::RemoveChildView(View* a_view) {
583 DoRemoveChildView(a_view, true, true, false);
584}
585
586void View::RemoveAllChildViews(bool delete_views) {
587 ViewList::iterator iter;
588 while ((iter = child_views_.begin()) != child_views_.end()) {
589 DoRemoveChildView(*iter, false, false, delete_views);
590 }
591 UpdateTooltip();
592}
593
[email protected]e9adf0702010-03-08 23:34:07594void View::DoDrag(const MouseEvent& e, const gfx::Point& press_pt) {
595 int drag_operations = GetDragOperations(press_pt);
[email protected]4768c65b2009-08-28 21:42:59596 if (drag_operations == DragDropTypes::DRAG_NONE)
597 return;
598
599 OSExchangeData data;
[email protected]e9adf0702010-03-08 23:34:07600 WriteDragData(press_pt, &data);
[email protected]4768c65b2009-08-28 21:42:59601
602 // Message the RootView to do the drag and drop. That way if we're removed
603 // the RootView can detect it and avoid calling us back.
604 RootView* root_view = GetRootView();
605 root_view->StartDragForViewFromMouseEvent(this, data, drag_operations);
606}
607
initial.commit09911bf2008-07-26 23:55:29608void View::DoRemoveChildView(View* a_view,
609 bool update_focus_cycle,
610 bool update_tool_tip,
611 bool delete_removed_view) {
612#ifndef NDEBUG
613 DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
614 "during a paint, this will seriously " <<
615 "mess things up!";
616#endif
617 DCHECK(a_view);
618 const ViewList::iterator i = find(child_views_.begin(),
619 child_views_.end(),
620 a_view);
621 if (i != child_views_.end()) {
[email protected]0d52b2302009-05-11 23:50:55622 if (update_focus_cycle) {
initial.commit09911bf2008-07-26 23:55:29623 // Let's remove the view from the focus traversal.
624 View* next_focusable = a_view->next_focusable_view_;
625 View* prev_focusable = a_view->previous_focusable_view_;
626 if (prev_focusable)
627 prev_focusable->next_focusable_view_ = next_focusable;
628 if (next_focusable)
629 next_focusable->previous_focusable_view_ = prev_focusable;
630 }
631
632 RootView* root = GetRootView();
633 if (root)
[email protected]7e7c82a2010-06-15 20:10:16634 UnregisterChildrenForRootNotifications(root, a_view);
initial.commit09911bf2008-07-26 23:55:29635 a_view->PropagateRemoveNotifications(this);
636 a_view->SetParent(NULL);
637
638 if (delete_removed_view && a_view->IsParentOwned())
639 delete a_view;
640
641 child_views_.erase(i);
642 }
643
644 if (update_tool_tip)
645 UpdateTooltip();
646
647 if (layout_manager_.get())
648 layout_manager_->ViewRemoved(this, a_view);
649}
650
651void View::PropagateRemoveNotifications(View* parent) {
[email protected]09fe9492009-11-07 02:23:06652 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29653 GetChildViewAt(i)->PropagateRemoveNotifications(parent);
initial.commit09911bf2008-07-26 23:55:29654
[email protected]09fe9492009-11-07 02:23:06655 for (View* v = this; v; v = v->GetParent())
656 v->ViewHierarchyChangedImpl(true, false, parent, this);
initial.commit09911bf2008-07-26 23:55:29657}
658
659void View::PropagateAddNotifications(View* parent, View* child) {
[email protected]09fe9492009-11-07 02:23:06660 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29661 GetChildViewAt(i)->PropagateAddNotifications(parent, child);
initial.commit09911bf2008-07-26 23:55:29662 ViewHierarchyChangedImpl(true, true, parent, child);
663}
664
[email protected]32670b02009-03-03 00:28:00665void View::ThemeChanged() {
[email protected]b2b718012010-03-25 15:09:06666 for (int i = GetChildViewCount() - 1; i >= 0; --i)
[email protected]32670b02009-03-03 00:28:00667 GetChildViewAt(i)->ThemeChanged();
668}
669
[email protected]7ceeba72010-04-20 18:22:12670void View::NotifyLocaleChanged() {
671 LocaleChanged();
[email protected]b2b718012010-03-25 15:09:06672 for (int i = GetChildViewCount() - 1; i >= 0; --i)
[email protected]7ceeba72010-04-20 18:22:12673 GetChildViewAt(i)->NotifyLocaleChanged();
[email protected]b2b718012010-03-25 15:09:06674}
675
initial.commit09911bf2008-07-26 23:55:29676#ifndef NDEBUG
677bool View::IsProcessingPaint() const {
678 return GetParent() && GetParent()->IsProcessingPaint();
679}
680#endif
681
[email protected]f704ee72008-11-10 21:31:59682gfx::Point View::GetKeyboardContextMenuLocation() {
683 gfx::Rect vis_bounds = GetVisibleBounds();
684 gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
685 vis_bounds.y() + vis_bounds.height() / 2);
686 ConvertPointToScreen(this, &screen_point);
687 return screen_point;
688}
689
[email protected]82739cf2008-09-16 00:37:56690bool View::HasHitTestMask() const {
691 return false;
692}
693
694void View::GetHitTestMask(gfx::Path* mask) const {
695 DCHECK(mask);
696}
697
[email protected]bb515ed2009-01-15 00:53:43698void View::ViewHierarchyChanged(bool is_add,
699 View* parent,
700 View* child) {
initial.commit09911bf2008-07-26 23:55:29701}
702
703void View::ViewHierarchyChangedImpl(bool register_accelerators,
[email protected]bb515ed2009-01-15 00:53:43704 bool is_add,
705 View* parent,
706 View* child) {
initial.commit09911bf2008-07-26 23:55:29707 if (register_accelerators) {
708 if (is_add) {
709 // If you get this registration, you are part of a subtree that has been
710 // added to the view hierarchy.
[email protected]bda9556c2010-01-07 00:55:16711 if (GetFocusManager()) {
712 RegisterPendingAccelerators();
713 } else {
714 // Delay accelerator registration until visible as we do not have
715 // focus manager until then.
716 accelerator_registration_delayed_ = true;
717 }
initial.commit09911bf2008-07-26 23:55:29718 } else {
719 if (child == this)
[email protected]fa1cf0b82010-01-15 21:49:44720 UnregisterAccelerators(true);
initial.commit09911bf2008-07-26 23:55:29721 }
722 }
723
724 ViewHierarchyChanged(is_add, parent, child);
725}
726
727void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
[email protected]09fe9492009-11-07 02:23:06728 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29729 GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
initial.commit09911bf2008-07-26 23:55:29730 VisibilityChanged(start, is_visible);
731}
732
733void View::VisibilityChanged(View* starting_from, bool is_visible) {
734}
735
[email protected]bda9556c2010-01-07 00:55:16736void View::PropagateNativeViewHierarchyChanged(bool attached,
737 gfx::NativeView native_view,
738 RootView* root_view) {
739 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
740 GetChildViewAt(i)->PropagateNativeViewHierarchyChanged(attached,
741 native_view,
742 root_view);
743 NativeViewHierarchyChanged(attached, native_view, root_view);
744}
745
746void View::NativeViewHierarchyChanged(bool attached,
747 gfx::NativeView native_view,
748 RootView* root_view) {
749 FocusManager* focus_manager = GetFocusManager();
750 if (!accelerator_registration_delayed_ &&
751 accelerator_focus_manager_ &&
752 accelerator_focus_manager_ != focus_manager) {
753 UnregisterAccelerators(true);
754 accelerator_registration_delayed_ = true;
755 }
756 if (accelerator_registration_delayed_ && attached) {
757 if (focus_manager) {
758 RegisterPendingAccelerators();
759 accelerator_registration_delayed_ = false;
760 }
761 }
762}
763
initial.commit09911bf2008-07-26 23:55:29764void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
765 if (notify_when_visible_bounds_in_root_changes_ == value)
766 return;
767 notify_when_visible_bounds_in_root_changes_ = value;
768 RootView* root = GetRootView();
769 if (root) {
770 if (value)
771 root->RegisterViewForVisibleBoundsNotification(this);
772 else
773 root->UnregisterViewForVisibleBoundsNotification(this);
774 }
775}
776
777bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
778 return notify_when_visible_bounds_in_root_changes_;
779}
780
[email protected]0d52b2302009-05-11 23:50:55781View* View::GetViewForPoint(const gfx::Point& point) {
initial.commit09911bf2008-07-26 23:55:29782 // Walk the child Views recursively looking for the View that most
783 // tightly encloses the specified point.
[email protected]09fe9492009-11-07 02:23:06784 for (int i = GetChildViewCount() - 1; i >= 0; --i) {
initial.commit09911bf2008-07-26 23:55:29785 View* child = GetChildViewAt(i);
[email protected]82739cf2008-09-16 00:37:56786 if (!child->IsVisible())
initial.commit09911bf2008-07-26 23:55:29787 continue;
[email protected]82739cf2008-09-16 00:37:56788
[email protected]96b667d2008-10-14 20:58:44789 gfx::Point point_in_child_coords(point);
[email protected]82739cf2008-09-16 00:37:56790 View::ConvertPointToView(this, child, &point_in_child_coords);
[email protected]613b8062008-10-14 23:45:09791 if (child->HitTest(point_in_child_coords))
[email protected]0d52b2302009-05-11 23:50:55792 return child->GetViewForPoint(point_in_child_coords);
initial.commit09911bf2008-07-26 23:55:29793 }
794 return this;
795}
796
[email protected]a0dde122008-11-21 20:51:20797Widget* View::GetWidget() const {
798 // The root view holds a reference to this view hierarchy's Widget.
799 return parent_ ? parent_->GetWidget() : NULL;
initial.commit09911bf2008-07-26 23:55:29800}
801
[email protected]cd8c47902009-04-30 20:55:35802Window* View::GetWindow() const {
803 Widget* widget = GetWidget();
804 return widget ? widget->GetWindow() : NULL;
805}
806
[email protected]2db27be2010-02-10 22:46:47807bool View::ContainsNativeView(gfx::NativeView native_view) const {
808 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
809 if (GetChildViewAt(i)->ContainsNativeView(native_view))
810 return true;
811 }
812 return false;
813}
814
initial.commit09911bf2008-07-26 23:55:29815// Get the containing RootView
816RootView* View::GetRootView() {
[email protected]a0dde122008-11-21 20:51:20817 Widget* widget = GetWidget();
818 return widget ? widget->GetRootView() : NULL;
initial.commit09911bf2008-07-26 23:55:29819}
820
821View* View::GetViewByID(int id) const {
822 if (id == id_)
823 return const_cast<View*>(this);
824
[email protected]09fe9492009-11-07 02:23:06825 for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
initial.commit09911bf2008-07-26 23:55:29826 View* child = GetChildViewAt(i);
827 View* view = child->GetViewByID(id);
828 if (view)
829 return view;
830 }
831 return NULL;
832}
833
834void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
835 if (group_ == group_id)
836 out->push_back(this);
837
[email protected]09fe9492009-11-07 02:23:06838 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29839 GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
840}
841
842View* View::GetSelectedViewForGroup(int group_id) {
843 std::vector<View*> views;
844 GetRootView()->GetViewsWithGroup(group_id, &views);
845 if (views.size() > 0)
846 return views[0];
847 else
848 return NULL;
849}
850
851void View::SetID(int id) {
852 id_ = id;
853}
854
855int View::GetID() const {
856 return id_;
857}
858
859void View::SetGroup(int gid) {
[email protected]96f960d2009-09-14 18:45:30860 // Don't change the group id once it's set.
861 DCHECK(group_ == -1 || group_ == gid);
initial.commit09911bf2008-07-26 23:55:29862 group_ = gid;
863}
864
865int View::GetGroup() const {
866 return group_;
867}
868
869void View::SetParent(View* parent) {
[email protected]09fe9492009-11-07 02:23:06870 if (parent != parent_)
initial.commit09911bf2008-07-26 23:55:29871 parent_ = parent;
initial.commit09911bf2008-07-26 23:55:29872}
873
874bool View::IsParentOf(View* v) const {
875 DCHECK(v);
876 View* parent = v->GetParent();
877 while (parent) {
878 if (this == parent)
879 return true;
880 parent = parent->GetParent();
881 }
882 return false;
883}
884
[email protected]5e26d9d42010-05-13 22:11:03885int View::GetChildIndex(const View* v) const {
[email protected]09fe9492009-11-07 02:23:06886 for (int i = 0, count = GetChildViewCount(); i < count; i++) {
initial.commit09911bf2008-07-26 23:55:29887 if (v == GetChildViewAt(i))
888 return i;
889 }
890 return -1;
891}
892
893///////////////////////////////////////////////////////////////////////////////
894//
895// View - focus
896//
897///////////////////////////////////////////////////////////////////////////////
898
899View* View::GetNextFocusableView() {
900 return next_focusable_view_;
901}
902
903View* View::GetPreviousFocusableView() {
904 return previous_focusable_view_;
905}
906
907void View::SetNextFocusableView(View* view) {
908 view->previous_focusable_view_ = this;
909 next_focusable_view_ = view;
910}
911
912void View::InitFocusSiblings(View* v, int index) {
913 int child_count = static_cast<int>(child_views_.size());
914
915 if (child_count == 0) {
916 v->next_focusable_view_ = NULL;
917 v->previous_focusable_view_ = NULL;
918 } else {
919 if (index == child_count) {
920 // We are inserting at the end, but the end of the child list may not be
921 // the last focusable element. Let's try to find an element with no next
922 // focusable element to link to.
923 View* last_focusable_view = NULL;
924 for (std::vector<View*>::iterator iter = child_views_.begin();
925 iter != child_views_.end(); ++iter) {
926 if (!(*iter)->next_focusable_view_) {
927 last_focusable_view = *iter;
928 break;
929 }
930 }
931 if (last_focusable_view == NULL) {
932 // Hum... there is a cycle in the focus list. Let's just insert ourself
933 // after the last child.
934 View* prev = child_views_[index - 1];
935 v->previous_focusable_view_ = prev;
936 v->next_focusable_view_ = prev->next_focusable_view_;
937 prev->next_focusable_view_->previous_focusable_view_ = v;
938 prev->next_focusable_view_ = v;
939 } else {
940 last_focusable_view->next_focusable_view_ = v;
941 v->next_focusable_view_ = NULL;
942 v->previous_focusable_view_ = last_focusable_view;
943 }
944 } else {
945 View* prev = child_views_[index]->GetPreviousFocusableView();
946 v->previous_focusable_view_ = prev;
947 v->next_focusable_view_ = child_views_[index];
948 if (prev)
949 prev->next_focusable_view_ = v;
950 child_views_[index]->previous_focusable_view_ = v;
951 }
952 }
953}
954
955#ifndef NDEBUG
956void View::PrintViewHierarchy() {
957 PrintViewHierarchyImp(0);
958}
959
960void View::PrintViewHierarchyImp(int indent) {
961 std::wostringstream buf;
962 int ind = indent;
963 while (ind-- > 0)
964 buf << L' ';
965 buf << UTF8ToWide(GetClassName());
966 buf << L' ';
967 buf << GetID();
968 buf << L' ';
[email protected]80f8b9f2008-10-16 18:17:47969 buf << bounds_.x() << L"," << bounds_.y() << L",";
970 buf << bounds_.right() << L"," << bounds_.bottom();
initial.commit09911bf2008-07-26 23:55:29971 buf << L' ';
972 buf << this;
973
974 LOG(INFO) << buf.str();
975 std::cout << buf.str() << std::endl;
976
[email protected]09fe9492009-11-07 02:23:06977 for (int i = 0, count = GetChildViewCount(); i < count; ++i)
initial.commit09911bf2008-07-26 23:55:29978 GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
initial.commit09911bf2008-07-26 23:55:29979}
980
981
982void View::PrintFocusHierarchy() {
983 PrintFocusHierarchyImp(0);
984}
985
986void View::PrintFocusHierarchyImp(int indent) {
987 std::wostringstream buf;
988 int ind = indent;
989 while (ind-- > 0)
990 buf << L' ';
991 buf << UTF8ToWide(GetClassName());
992 buf << L' ';
993 buf << GetID();
994 buf << L' ';
995 buf << GetClassName().c_str();
996 buf << L' ';
997 buf << this;
998
999 LOG(INFO) << buf.str();
1000 std::cout << buf.str() << std::endl;
1001
1002 if (GetChildViewCount() > 0)
1003 GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
1004
1005 View* v = GetNextFocusableView();
1006 if (v)
1007 v->PrintFocusHierarchyImp(indent);
1008}
1009#endif
1010
1011////////////////////////////////////////////////////////////////////////////////
1012//
1013// View - accelerators
1014//
1015////////////////////////////////////////////////////////////////////////////////
1016
1017void View::AddAccelerator(const Accelerator& accelerator) {
1018 if (!accelerators_.get())
1019 accelerators_.reset(new std::vector<Accelerator>());
[email protected]71421c3f2009-06-06 00:41:441020
1021 std::vector<Accelerator>::iterator iter =
1022 std::find(accelerators_->begin(), accelerators_->end(), accelerator);
1023 DCHECK(iter == accelerators_->end())
1024 << "Registering the same accelerator multiple times";
1025
initial.commit09911bf2008-07-26 23:55:291026 accelerators_->push_back(accelerator);
[email protected]71421c3f2009-06-06 00:41:441027 RegisterPendingAccelerators();
initial.commit09911bf2008-07-26 23:55:291028}
1029
[email protected]e8e0f362008-11-08 01:13:251030void View::RemoveAccelerator(const Accelerator& accelerator) {
1031 std::vector<Accelerator>::iterator iter;
1032 if (!accelerators_.get() ||
1033 ((iter = std::find(accelerators_->begin(), accelerators_->end(),
1034 accelerator)) == accelerators_->end())) {
1035 NOTREACHED() << "Removing non-existing accelerator";
1036 return;
1037 }
1038
[email protected]4bd23f32009-06-08 20:59:191039 size_t index = iter - accelerators_->begin();
[email protected]e8e0f362008-11-08 01:13:251040 accelerators_->erase(iter);
[email protected]71421c3f2009-06-06 00:41:441041 if (index >= registered_accelerator_count_) {
1042 // The accelerator is not registered to FocusManager.
1043 return;
1044 }
1045 --registered_accelerator_count_;
1046
[email protected]e8e0f362008-11-08 01:13:251047 RootView* root_view = GetRootView();
1048 if (!root_view) {
1049 // We are not part of a view hierarchy, so there is nothing to do as we
1050 // removed ourselves from accelerators_, we won't be registered when added
1051 // to one.
1052 return;
1053 }
1054
[email protected]bda9556c2010-01-07 00:55:161055 // If accelerator_focus_manager_ is NULL then we did not registered
1056 // accelerators so there is nothing to unregister.
1057 if (accelerator_focus_manager_) {
1058 accelerator_focus_manager_->UnregisterAccelerator(accelerator, this);
[email protected]e8e0f362008-11-08 01:13:251059 }
1060}
1061
initial.commit09911bf2008-07-26 23:55:291062void View::ResetAccelerators() {
[email protected]71421c3f2009-06-06 00:41:441063 if (accelerators_.get())
[email protected]bda9556c2010-01-07 00:55:161064 UnregisterAccelerators(false);
initial.commit09911bf2008-07-26 23:55:291065}
1066
[email protected]71421c3f2009-06-06 00:41:441067void View::RegisterPendingAccelerators() {
1068 if (!accelerators_.get() ||
1069 registered_accelerator_count_ == accelerators_->size()) {
1070 // No accelerators are waiting for registration.
initial.commit09911bf2008-07-26 23:55:291071 return;
[email protected]71421c3f2009-06-06 00:41:441072 }
initial.commit09911bf2008-07-26 23:55:291073
1074 RootView* root_view = GetRootView();
1075 if (!root_view) {
1076 // We are not yet part of a view hierarchy, we'll register ourselves once
1077 // added to one.
1078 return;
1079 }
[email protected]f3735c5d2009-03-19 17:26:231080
[email protected]bda9556c2010-01-07 00:55:161081 accelerator_focus_manager_ = GetFocusManager();
1082 if (!accelerator_focus_manager_) {
initial.commit09911bf2008-07-26 23:55:291083 // Some crash reports seem to show that we may get cases where we have no
1084 // focus manager (see bug #1291225). This should never be the case, just
1085 // making sure we don't crash.
[email protected]f8dce002009-09-10 21:07:041086
1087 // TODO(jcampan): This fails for a view under WidgetGtk with TYPE_CHILD.
1088 // (see http://crbug.com/21335) reenable NOTREACHED assertion and
1089 // verify accelerators works as expected.
1090#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:291091 NOTREACHED();
[email protected]f8dce002009-09-10 21:07:041092#endif
initial.commit09911bf2008-07-26 23:55:291093 return;
1094 }
[email protected]71421c3f2009-06-06 00:41:441095 std::vector<Accelerator>::const_iterator iter;
1096 for (iter = accelerators_->begin() + registered_accelerator_count_;
initial.commit09911bf2008-07-26 23:55:291097 iter != accelerators_->end(); ++iter) {
[email protected]bda9556c2010-01-07 00:55:161098 accelerator_focus_manager_->RegisterAccelerator(*iter, this);
initial.commit09911bf2008-07-26 23:55:291099 }
[email protected]71421c3f2009-06-06 00:41:441100 registered_accelerator_count_ = accelerators_->size();
initial.commit09911bf2008-07-26 23:55:291101}
1102
[email protected]bda9556c2010-01-07 00:55:161103void View::UnregisterAccelerators(bool leave_data_intact) {
initial.commit09911bf2008-07-26 23:55:291104 if (!accelerators_.get())
1105 return;
1106
1107 RootView* root_view = GetRootView();
1108 if (root_view) {
[email protected]bda9556c2010-01-07 00:55:161109 if (accelerator_focus_manager_) {
initial.commit09911bf2008-07-26 23:55:291110 // We may not have a FocusManager if the window containing us is being
1111 // closed, in which case the FocusManager is being deleted so there is
1112 // nothing to unregister.
[email protected]bda9556c2010-01-07 00:55:161113 accelerator_focus_manager_->UnregisterAccelerators(this);
1114 accelerator_focus_manager_ = NULL;
initial.commit09911bf2008-07-26 23:55:291115 }
[email protected]bda9556c2010-01-07 00:55:161116 if (!leave_data_intact) {
1117 accelerators_->clear();
1118 accelerators_.reset();
1119 }
[email protected]71421c3f2009-06-06 00:41:441120 registered_accelerator_count_ = 0;
initial.commit09911bf2008-07-26 23:55:291121 }
1122}
1123
[email protected]e9adf0702010-03-08 23:34:071124int View::GetDragOperations(const gfx::Point& press_pt) {
1125 return drag_controller_ ?
1126 drag_controller_->GetDragOperations(this, press_pt) :
1127 DragDropTypes::DRAG_NONE;
initial.commit09911bf2008-07-26 23:55:291128}
1129
[email protected]e9adf0702010-03-08 23:34:071130void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) {
initial.commit09911bf2008-07-26 23:55:291131 DCHECK(drag_controller_);
[email protected]e9adf0702010-03-08 23:34:071132 drag_controller_->WriteDragData(this, press_pt, data);
initial.commit09911bf2008-07-26 23:55:291133}
1134
1135void View::OnDragDone() {
1136}
1137
1138bool View::InDrag() {
1139 RootView* root_view = GetRootView();
1140 return root_view ? (root_view->GetDragView() == this) : false;
1141}
1142
[email protected]d5c81012010-04-03 00:56:121143bool View::GetAccessibleName(std::wstring* name) {
1144 DCHECK(name);
1145
1146 if (accessible_name_.empty())
1147 return false;
1148 *name = accessible_name_;
1149 return true;
1150}
1151
[email protected]b82a0492010-05-27 23:00:031152bool View::GetAccessibleRole(AccessibilityTypes::Role* role) {
1153 if (accessible_role_) {
1154 *role = accessible_role_;
1155 return true;
1156 }
1157 return false;
1158}
1159
[email protected]d5c81012010-04-03 00:56:121160void View::SetAccessibleName(const std::wstring& name) {
1161 accessible_name_ = name;
1162}
1163
[email protected]b82a0492010-05-27 23:00:031164void View::SetAccessibleRole(const AccessibilityTypes::Role role) {
1165 accessible_role_ = role;
1166}
1167
initial.commit09911bf2008-07-26 23:55:291168// static
[email protected]bb515ed2009-01-15 00:53:431169void View::ConvertPointToView(const View* src,
1170 const View* dst,
1171 gfx::Point* point) {
initial.commit09911bf2008-07-26 23:55:291172 ConvertPointToView(src, dst, point, true);
1173}
1174
1175// static
[email protected]bb515ed2009-01-15 00:53:431176void View::ConvertPointToView(const View* src,
1177 const View* dst,
1178 gfx::Point* point,
initial.commit09911bf2008-07-26 23:55:291179 bool try_other_direction) {
1180 // src can be NULL
1181 DCHECK(dst);
1182 DCHECK(point);
1183
[email protected]bb515ed2009-01-15 00:53:431184 const View* v;
initial.commit09911bf2008-07-26 23:55:291185 gfx::Point offset;
1186
1187 for (v = dst; v && v != src; v = v->GetParent()) {
1188 offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
[email protected]6f3bb6c2008-09-17 22:25:331189 offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291190 }
1191
1192 // The source was not found. The caller wants a conversion
1193 // from a view to a transitive parent.
1194 if (src && v == NULL && try_other_direction) {
1195 gfx::Point p;
1196 // note: try_other_direction is force to FALSE so we don't
1197 // end up in an infinite recursion should both src and dst
1198 // are not parented.
1199 ConvertPointToView(dst, src, &p, false);
1200 // since the src and dst are inverted, p should also be negated
1201 point->SetPoint(point->x() - p.x(), point->y() - p.y());
1202 } else {
1203 point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
1204
1205 // If src is NULL, sp is in the screen coordinate system
1206 if (src == NULL) {
[email protected]a0dde122008-11-21 20:51:201207 Widget* widget = dst->GetWidget();
1208 if (widget) {
[email protected]3b680a82008-12-17 02:03:231209 gfx::Rect b;
[email protected]a0dde122008-11-21 20:51:201210 widget->GetBounds(&b, false);
[email protected]3b680a82008-12-17 02:03:231211 point->SetPoint(point->x() - b.x(), point->y() - b.y());
initial.commit09911bf2008-07-26 23:55:291212 }
1213 }
1214 }
1215}
1216
1217// static
[email protected]2fb6d462009-02-13 18:40:101218void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291219 DCHECK(src);
1220 DCHECK(p);
[email protected]96b667d2008-10-14 20:58:441221
[email protected]96b667d2008-10-14 20:58:441222 gfx::Point offset;
[email protected]2fb6d462009-02-13 18:40:101223 for (const View* v = src; v; v = v->GetParent()) {
[email protected]96b667d2008-10-14 20:58:441224 offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION));
1225 offset.set_y(offset.y() + v->y());
initial.commit09911bf2008-07-26 23:55:291226 }
[email protected]96b667d2008-10-14 20:58:441227 p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
initial.commit09911bf2008-07-26 23:55:291228}
1229
1230// static
[email protected]2fb6d462009-02-13 18:40:101231void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
[email protected]96b667d2008-10-14 20:58:441232 gfx::Point t;
[email protected]2fb6d462009-02-13 18:40:101233 ConvertPointToWidget(dest, &t);
[email protected]96b667d2008-10-14 20:58:441234 p->SetPoint(p->x() - t.x(), p->y() - t.y());
initial.commit09911bf2008-07-26 23:55:291235}
1236
1237// static
[email protected]2fb6d462009-02-13 18:40:101238void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
initial.commit09911bf2008-07-26 23:55:291239 DCHECK(src);
1240 DCHECK(p);
1241
[email protected]96b667d2008-10-14 20:58:441242 // If the view is not connected to a tree, there's nothing we can do.
[email protected]a0dde122008-11-21 20:51:201243 Widget* widget = src->GetWidget();
1244 if (widget) {
1245 ConvertPointToWidget(src, p);
[email protected]3b680a82008-12-17 02:03:231246 gfx::Rect r;
[email protected]a0dde122008-11-21 20:51:201247 widget->GetBounds(&r, false);
[email protected]3b680a82008-12-17 02:03:231248 p->SetPoint(p->x() + r.x(), p->y() + r.y());
initial.commit09911bf2008-07-26 23:55:291249 }
1250}
1251
1252/////////////////////////////////////////////////////////////////////////////
1253//
1254// View - event handlers
1255//
1256/////////////////////////////////////////////////////////////////////////////
1257
1258bool View::OnMousePressed(const MouseEvent& e) {
1259 return false;
1260}
1261
1262bool View::OnMouseDragged(const MouseEvent& e) {
1263 return false;
1264}
1265
1266void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
1267}
1268
1269void View::OnMouseMoved(const MouseEvent& e) {
1270}
1271
1272void View::OnMouseEntered(const MouseEvent& e) {
1273}
1274
1275void View::OnMouseExited(const MouseEvent& e) {
1276}
1277
1278void View::SetMouseHandler(View *new_mouse_handler) {
1279 // It is valid for new_mouse_handler to be NULL
[email protected]09fe9492009-11-07 02:23:061280 if (parent_)
initial.commit09911bf2008-07-26 23:55:291281 parent_->SetMouseHandler(new_mouse_handler);
initial.commit09911bf2008-07-26 23:55:291282}
1283
1284void View::SetVisible(bool flag) {
1285 if (flag != is_visible_) {
1286 // If the tab is currently visible, schedule paint to
1287 // refresh parent
[email protected]09fe9492009-11-07 02:23:061288 if (IsVisible())
initial.commit09911bf2008-07-26 23:55:291289 SchedulePaint();
initial.commit09911bf2008-07-26 23:55:291290
1291 is_visible_ = flag;
1292
1293 // This notifies all subviews recursively.
1294 PropagateVisibilityNotifications(this, flag);
1295
1296 // If we are newly visible, schedule paint.
[email protected]09fe9492009-11-07 02:23:061297 if (IsVisible())
initial.commit09911bf2008-07-26 23:55:291298 SchedulePaint();
initial.commit09911bf2008-07-26 23:55:291299 }
1300}
1301
1302bool View::IsVisibleInRootView() const {
1303 View* parent = GetParent();
1304 if (IsVisible() && parent)
1305 return parent->IsVisibleInRootView();
1306 else
1307 return false;
1308}
1309
initial.commit09911bf2008-07-26 23:55:291310/////////////////////////////////////////////////////////////////////////////
1311//
1312// View - keyboard and focus
1313//
1314/////////////////////////////////////////////////////////////////////////////
1315
1316void View::RequestFocus() {
1317 RootView* rv = GetRootView();
[email protected]830e2062009-02-13 18:27:381318 if (rv && IsFocusable())
initial.commit09911bf2008-07-26 23:55:291319 rv->FocusView(this);
initial.commit09911bf2008-07-26 23:55:291320}
1321
1322void View::WillGainFocus() {
1323}
1324
1325void View::DidGainFocus() {
1326}
1327
1328void View::WillLoseFocus() {
1329}
1330
1331bool View::OnKeyPressed(const KeyEvent& e) {
1332 return false;
1333}
1334
1335bool View::OnKeyReleased(const KeyEvent& e) {
1336 return false;
1337}
1338
1339bool View::OnMouseWheel(const MouseWheelEvent& e) {
1340 return false;
1341}
1342
1343void View::SetDragController(DragController* drag_controller) {
[email protected]09fe9492009-11-07 02:23:061344 drag_controller_ = drag_controller;
initial.commit09911bf2008-07-26 23:55:291345}
1346
1347DragController* View::GetDragController() {
1348 return drag_controller_;
1349}
1350
[email protected]134c47b92009-08-19 03:33:441351bool View::GetDropFormats(
1352 int* formats,
1353 std::set<OSExchangeData::CustomFormat>* custom_formats) {
1354 return false;
1355}
1356
1357bool View::AreDropTypesRequired() {
1358 return false;
1359}
1360
initial.commit09911bf2008-07-26 23:55:291361bool View::CanDrop(const OSExchangeData& data) {
[email protected]134c47b92009-08-19 03:33:441362 // TODO(sky): when I finish up migration, this should default to true.
initial.commit09911bf2008-07-26 23:55:291363 return false;
1364}
1365
1366void View::OnDragEntered(const DropTargetEvent& event) {
1367}
1368
1369int View::OnDragUpdated(const DropTargetEvent& event) {
1370 return DragDropTypes::DRAG_NONE;
1371}
1372
1373void View::OnDragExited() {
1374}
1375
1376int View::OnPerformDrop(const DropTargetEvent& event) {
1377 return DragDropTypes::DRAG_NONE;
1378}
1379
initial.commit09911bf2008-07-26 23:55:291380// static
1381bool View::ExceededDragThreshold(int delta_x, int delta_y) {
1382 return (abs(delta_x) > GetHorizontalDragThreshold() ||
1383 abs(delta_y) > GetVerticalDragThreshold());
1384}
1385
initial.commit09911bf2008-07-26 23:55:291386// Tooltips -----------------------------------------------------------------
[email protected]e9adf0702010-03-08 23:34:071387bool View::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
initial.commit09911bf2008-07-26 23:55:291388 return false;
1389}
1390
[email protected]e9adf0702010-03-08 23:34:071391bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) {
initial.commit09911bf2008-07-26 23:55:291392 return false;
1393}
1394
1395void View::TooltipTextChanged() {
[email protected]a0dde122008-11-21 20:51:201396 Widget* widget = GetWidget();
1397 if (widget && widget->GetTooltipManager())
1398 widget->GetTooltipManager()->TooltipTextChanged(this);
initial.commit09911bf2008-07-26 23:55:291399}
1400
1401void View::UpdateTooltip() {
[email protected]a0dde122008-11-21 20:51:201402 Widget* widget = GetWidget();
1403 if (widget && widget->GetTooltipManager())
1404 widget->GetTooltipManager()->UpdateTooltip();
initial.commit09911bf2008-07-26 23:55:291405}
1406
initial.commit09911bf2008-07-26 23:55:291407std::string View::GetClassName() const {
1408 return kViewClassName;
1409}
1410
[email protected]5c2b98b2009-03-09 20:55:541411View* View::GetAncestorWithClassName(const std::string& name) {
1412 for (View* view = this; view; view = view->GetParent()) {
1413 if (view->GetClassName() == name)
1414 return view;
1415 }
1416 return NULL;
1417}
1418
initial.commit09911bf2008-07-26 23:55:291419gfx::Rect View::GetVisibleBounds() {
[email protected]b6296fd2009-02-13 17:34:161420 if (!IsVisibleInRootView())
1421 return gfx::Rect();
[email protected]6f3bb6c2008-09-17 22:25:331422 gfx::Rect vis_bounds(0, 0, width(), height());
initial.commit09911bf2008-07-26 23:55:291423 gfx::Rect ancestor_bounds;
1424 View* view = this;
1425 int root_x = 0;
1426 int root_y = 0;
initial.commit09911bf2008-07-26 23:55:291427 while (view != NULL && !vis_bounds.IsEmpty()) {
1428 root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
[email protected]6f3bb6c2008-09-17 22:25:331429 root_y += view->y();
1430 vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y());
initial.commit09911bf2008-07-26 23:55:291431 View* ancestor = view->GetParent();
1432 if (ancestor != NULL) {
[email protected]6f3bb6c2008-09-17 22:25:331433 ancestor_bounds.SetRect(0, 0, ancestor->width(),
1434 ancestor->height());
initial.commit09911bf2008-07-26 23:55:291435 vis_bounds = vis_bounds.Intersect(ancestor_bounds);
[email protected]a0dde122008-11-21 20:51:201436 } else if (!view->GetWidget()) {
1437 // If the view has no Widget, we're not visible. Return an empty rect.
initial.commit09911bf2008-07-26 23:55:291438 return gfx::Rect();
1439 }
1440 view = ancestor;
1441 }
1442 if (vis_bounds.IsEmpty())
1443 return vis_bounds;
1444 // Convert back to this views coordinate system.
1445 vis_bounds.Offset(-root_x, -root_y);
1446 return vis_bounds;
1447}
1448
1449int View::GetPageScrollIncrement(ScrollView* scroll_view,
1450 bool is_horizontal, bool is_positive) {
1451 return 0;
1452}
1453
1454int View::GetLineScrollIncrement(ScrollView* scroll_view,
1455 bool is_horizontal, bool is_positive) {
1456 return 0;
1457}
1458
[email protected]45da6c72009-10-28 20:45:421459ThemeProvider* View::GetThemeProvider() const {
[email protected]4a190632009-05-09 01:07:421460 Widget* widget = GetWidget();
1461 return widget ? widget->GetThemeProvider() : NULL;
1462}
1463
initial.commit09911bf2008-07-26 23:55:291464// static
[email protected]7e7c82a2010-06-15 20:10:161465void View::RegisterChildrenForRootNotifications(RootView* root, View* view) {
initial.commit09911bf2008-07-26 23:55:291466 DCHECK(root && view);
1467 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1468 root->RegisterViewForVisibleBoundsNotification(view);
[email protected]7e7c82a2010-06-15 20:10:161469 if (view->near_insets_.get())
1470 root->RegisterViewForNearNotification(view);
initial.commit09911bf2008-07-26 23:55:291471 for (int i = 0; i < view->GetChildViewCount(); ++i)
[email protected]7e7c82a2010-06-15 20:10:161472 RegisterChildrenForRootNotifications(root, view->GetChildViewAt(i));
initial.commit09911bf2008-07-26 23:55:291473}
1474
1475// static
[email protected]7e7c82a2010-06-15 20:10:161476void View::UnregisterChildrenForRootNotifications(
initial.commit09911bf2008-07-26 23:55:291477 RootView* root, View* view) {
1478 DCHECK(root && view);
1479 if (view->GetNotifyWhenVisibleBoundsInRootChanges())
1480 root->UnregisterViewForVisibleBoundsNotification(view);
[email protected]7e7c82a2010-06-15 20:10:161481 if (view->near_insets_.get())
1482 root->UnregisterViewForNearNotification(view);
initial.commit09911bf2008-07-26 23:55:291483 for (int i = 0; i < view->GetChildViewCount(); ++i)
[email protected]7e7c82a2010-06-15 20:10:161484 UnregisterChildrenForRootNotifications(root, view->GetChildViewAt(i));
initial.commit09911bf2008-07-26 23:55:291485}
1486
1487void View::AddDescendantToNotify(View* view) {
1488 DCHECK(view);
1489 if (!descendants_to_notify_.get())
1490 descendants_to_notify_.reset(new ViewList());
1491 descendants_to_notify_->push_back(view);
1492}
1493
1494void View::RemoveDescendantToNotify(View* view) {
1495 DCHECK(view && descendants_to_notify_.get());
1496 ViewList::iterator i = find(descendants_to_notify_->begin(),
1497 descendants_to_notify_->end(),
1498 view);
1499 DCHECK(i != descendants_to_notify_->end());
1500 descendants_to_notify_->erase(i);
1501 if (descendants_to_notify_->empty())
1502 descendants_to_notify_.reset();
1503}
1504
initial.commit09911bf2008-07-26 23:55:291505// DropInfo --------------------------------------------------------------------
1506
1507void View::DragInfo::Reset() {
1508 possible_drag = false;
[email protected]e9adf0702010-03-08 23:34:071509 start_pt = gfx::Point();
initial.commit09911bf2008-07-26 23:55:291510}
1511
[email protected]e9adf0702010-03-08 23:34:071512void View::DragInfo::PossibleDrag(const gfx::Point& p) {
initial.commit09911bf2008-07-26 23:55:291513 possible_drag = true;
[email protected]e9adf0702010-03-08 23:34:071514 start_pt = p;
initial.commit09911bf2008-07-26 23:55:291515}
1516
1517} // namespace