| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first. | |
| 6 | |
| 7 #include "ui/views/view.h" | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <cmath> | |
| 11 | |
| 12 #include "base/debug/trace_event.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/message_loop/message_loop.h" | |
| 16 #include "base/strings/stringprintf.h" | |
| 17 #include "base/strings/utf_string_conversions.h" | |
| 18 #include "third_party/skia/include/core/SkRect.h" | |
| 19 #include "ui/accessibility/ax_enums.h" | |
| 20 #include "ui/base/cursor/cursor.h" | |
| 21 #include "ui/base/dragdrop/drag_drop_types.h" | |
| 22 #include "ui/compositor/compositor.h" | |
| 23 #include "ui/compositor/dip_util.h" | |
| 24 #include "ui/compositor/layer.h" | |
| 25 #include "ui/compositor/layer_animator.h" | |
| 26 #include "ui/events/event_target_iterator.h" | |
| 27 #include "ui/gfx/canvas.h" | |
| 28 #include "ui/gfx/interpolated_transform.h" | |
| 29 #include "ui/gfx/path.h" | |
| 30 #include "ui/gfx/point3_f.h" | |
| 31 #include "ui/gfx/point_conversions.h" | |
| 32 #include "ui/gfx/scoped_canvas.h" | |
| 33 #include "ui/gfx/screen.h" | |
| 34 #include "ui/gfx/skia_util.h" | |
| 35 #include "ui/gfx/transform.h" | |
| 36 #include "ui/native_theme/native_theme.h" | |
| 37 #include "ui/views/accessibility/native_view_accessibility.h" | |
| 38 #include "ui/views/background.h" | |
| 39 #include "ui/views/border.h" | |
| 40 #include "ui/views/context_menu_controller.h" | |
| 41 #include "ui/views/drag_controller.h" | |
| 42 #include "ui/views/focus/view_storage.h" | |
| 43 #include "ui/views/layout/layout_manager.h" | |
| 44 #include "ui/views/views_delegate.h" | |
| 45 #include "ui/views/widget/native_widget_private.h" | |
| 46 #include "ui/views/widget/root_view.h" | |
| 47 #include "ui/views/widget/tooltip_manager.h" | |
| 48 #include "ui/views/widget/widget.h" | |
| 49 | |
| 50 #if defined(OS_WIN) | |
| 51 #include "base/win/scoped_gdi_object.h" | |
| 52 #endif | |
| 53 | |
| 54 namespace { | |
| 55 | |
| 56 #if defined(OS_WIN) | |
| 57 const bool kContextMenuOnMousePress = false; | |
| 58 #else | |
| 59 const bool kContextMenuOnMousePress = true; | |
| 60 #endif | |
| 61 | |
| 62 // Default horizontal drag threshold in pixels. | |
| 63 // Same as what gtk uses. | |
| 64 const int kDefaultHorizontalDragThreshold = 8; | |
| 65 | |
| 66 // Default vertical drag threshold in pixels. | |
| 67 // Same as what gtk uses. | |
| 68 const int kDefaultVerticalDragThreshold = 8; | |
| 69 | |
| 70 // Returns the top view in |view|'s hierarchy. | |
| 71 const views::View* GetHierarchyRoot(const views::View* view) { | |
| 72 const views::View* root = view; | |
| 73 while (root && root->parent()) | |
| 74 root = root->parent(); | |
| 75 return root; | |
| 76 } | |
| 77 | |
| 78 } // namespace | |
| 79 | |
| 80 namespace views { | |
| 81 | |
| 82 namespace internal { | |
| 83 | |
| 84 } // namespace internal | |
| 85 | |
| 86 // static | |
| 87 ViewsDelegate* ViewsDelegate::views_delegate = NULL; | |
| 88 | |
| 89 // static | |
| 90 const char View::kViewClassName[] = "View"; | |
| 91 | |
| 92 //////////////////////////////////////////////////////////////////////////////// | |
| 93 // View, public: | |
| 94 | |
| 95 // Creation and lifetime ------------------------------------------------------- | |
| 96 | |
| 97 View::View() | |
| 98 : owned_by_client_(false), | |
| 99 id_(0), | |
| 100 group_(-1), | |
| 101 parent_(NULL), | |
| 102 visible_(true), | |
| 103 enabled_(true), | |
| 104 notify_enter_exit_on_child_(false), | |
| 105 registered_for_visible_bounds_notification_(false), | |
| 106 root_bounds_dirty_(true), | |
| 107 clip_insets_(0, 0, 0, 0), | |
| 108 needs_layout_(true), | |
| 109 snap_layer_to_pixel_boundary_(false), | |
| 110 flip_canvas_on_paint_for_rtl_ui_(false), | |
| 111 paint_to_layer_(false), | |
| 112 accelerator_focus_manager_(NULL), | |
| 113 registered_accelerator_count_(0), | |
| 114 next_focusable_view_(NULL), | |
| 115 previous_focusable_view_(NULL), | |
| 116 focusable_(false), | |
| 117 accessibility_focusable_(false), | |
| 118 context_menu_controller_(NULL), | |
| 119 drag_controller_(NULL), | |
| 120 native_view_accessibility_(NULL) { | |
| 121 } | |
| 122 | |
| 123 View::~View() { | |
| 124 if (parent_) | |
| 125 parent_->RemoveChildView(this); | |
| 126 | |
| 127 ViewStorage::GetInstance()->ViewRemoved(this); | |
| 128 | |
| 129 for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) { | |
| 130 (*i)->parent_ = NULL; | |
| 131 if (!(*i)->owned_by_client_) | |
| 132 delete *i; | |
| 133 } | |
| 134 | |
| 135 // Release ownership of the native accessibility object, but it's | |
| 136 // reference-counted on some platforms, so it may not be deleted right away. | |
| 137 if (native_view_accessibility_) | |
| 138 native_view_accessibility_->Destroy(); | |
| 139 } | |
| 140 | |
| 141 // Tree operations ------------------------------------------------------------- | |
| 142 | |
| 143 const Widget* View::GetWidget() const { | |
| 144 // The root view holds a reference to this view hierarchy's Widget. | |
| 145 return parent_ ? parent_->GetWidget() : NULL; | |
| 146 } | |
| 147 | |
| 148 Widget* View::GetWidget() { | |
| 149 return const_cast<Widget*>(const_cast<const View*>(this)->GetWidget()); | |
| 150 } | |
| 151 | |
| 152 void View::AddChildView(View* view) { | |
| 153 if (view->parent_ == this) | |
| 154 return; | |
| 155 AddChildViewAt(view, child_count()); | |
| 156 } | |
| 157 | |
| 158 void View::AddChildViewAt(View* view, int index) { | |
| 159 CHECK_NE(view, this) << "You cannot add a view as its own child"; | |
| 160 DCHECK_GE(index, 0); | |
| 161 DCHECK_LE(index, child_count()); | |
| 162 | |
| 163 // If |view| has a parent, remove it from its parent. | |
| 164 View* parent = view->parent_; | |
| 165 ui::NativeTheme* old_theme = NULL; | |
| 166 if (parent) { | |
| 167 old_theme = view->GetNativeTheme(); | |
| 168 if (parent == this) { | |
| 169 ReorderChildView(view, index); | |
| 170 return; | |
| 171 } | |
| 172 parent->DoRemoveChildView(view, true, true, false, this); | |
| 173 } | |
| 174 | |
| 175 // Sets the prev/next focus views. | |
| 176 InitFocusSiblings(view, index); | |
| 177 | |
| 178 // Let's insert the view. | |
| 179 view->parent_ = this; | |
| 180 children_.insert(children_.begin() + index, view); | |
| 181 | |
| 182 // Instruct the view to recompute its root bounds on next Paint(). | |
| 183 view->SetRootBoundsDirty(true); | |
| 184 | |
| 185 views::Widget* widget = GetWidget(); | |
| 186 if (widget) { | |
| 187 const ui::NativeTheme* new_theme = view->GetNativeTheme(); | |
| 188 if (new_theme != old_theme) | |
| 189 view->PropagateNativeThemeChanged(new_theme); | |
| 190 } | |
| 191 | |
| 192 ViewHierarchyChangedDetails details(true, this, view, parent); | |
| 193 | |
| 194 for (View* v = this; v; v = v->parent_) | |
| 195 v->ViewHierarchyChangedImpl(false, details); | |
| 196 | |
| 197 view->PropagateAddNotifications(details); | |
| 198 UpdateTooltip(); | |
| 199 if (widget) { | |
| 200 RegisterChildrenForVisibleBoundsNotification(view); | |
| 201 if (view->visible()) | |
| 202 view->SchedulePaint(); | |
| 203 } | |
| 204 | |
| 205 if (layout_manager_.get()) | |
| 206 layout_manager_->ViewAdded(this, view); | |
| 207 | |
| 208 ReorderLayers(); | |
| 209 | |
| 210 // Make sure the visibility of the child layers are correct. | |
| 211 // If any of the parent View is hidden, then the layers of the subtree | |
| 212 // rooted at |this| should be hidden. Otherwise, all the child layers should | |
| 213 // inherit the visibility of the owner View. | |
| 214 UpdateLayerVisibility(); | |
| 215 } | |
| 216 | |
| 217 void View::ReorderChildView(View* view, int index) { | |
| 218 DCHECK_EQ(view->parent_, this); | |
| 219 if (index < 0) | |
| 220 index = child_count() - 1; | |
| 221 else if (index >= child_count()) | |
| 222 return; | |
| 223 if (children_[index] == view) | |
| 224 return; | |
| 225 | |
| 226 const Views::iterator i(std::find(children_.begin(), children_.end(), view)); | |
| 227 DCHECK(i != children_.end()); | |
| 228 children_.erase(i); | |
| 229 | |
| 230 // Unlink the view first | |
| 231 View* next_focusable = view->next_focusable_view_; | |
| 232 View* prev_focusable = view->previous_focusable_view_; | |
| 233 if (prev_focusable) | |
| 234 prev_focusable->next_focusable_view_ = next_focusable; | |
| 235 if (next_focusable) | |
| 236 next_focusable->previous_focusable_view_ = prev_focusable; | |
| 237 | |
| 238 // Add it in the specified index now. | |
| 239 InitFocusSiblings(view, index); | |
| 240 children_.insert(children_.begin() + index, view); | |
| 241 | |
| 242 ReorderLayers(); | |
| 243 } | |
| 244 | |
| 245 void View::RemoveChildView(View* view) { | |
| 246 DoRemoveChildView(view, true, true, false, NULL); | |
| 247 } | |
| 248 | |
| 249 void View::RemoveAllChildViews(bool delete_children) { | |
| 250 while (!children_.empty()) | |
| 251 DoRemoveChildView(children_.front(), false, false, delete_children, NULL); | |
| 252 UpdateTooltip(); | |
| 253 } | |
| 254 | |
| 255 bool View::Contains(const View* view) const { | |
| 256 for (const View* v = view; v; v = v->parent_) { | |
| 257 if (v == this) | |
| 258 return true; | |
| 259 } | |
| 260 return false; | |
| 261 } | |
| 262 | |
| 263 int View::GetIndexOf(const View* view) const { | |
| 264 Views::const_iterator i(std::find(children_.begin(), children_.end(), view)); | |
| 265 return i != children_.end() ? static_cast<int>(i - children_.begin()) : -1; | |
| 266 } | |
| 267 | |
| 268 // Size and disposition -------------------------------------------------------- | |
| 269 | |
| 270 void View::SetBounds(int x, int y, int width, int height) { | |
| 271 SetBoundsRect(gfx::Rect(x, y, std::max(0, width), std::max(0, height))); | |
| 272 } | |
| 273 | |
| 274 void View::SetBoundsRect(const gfx::Rect& bounds) { | |
| 275 if (bounds == bounds_) { | |
| 276 if (needs_layout_) { | |
| 277 needs_layout_ = false; | |
| 278 Layout(); | |
| 279 } | |
| 280 return; | |
| 281 } | |
| 282 | |
| 283 if (visible_) { | |
| 284 // Paint where the view is currently. | |
| 285 SchedulePaintBoundsChanged( | |
| 286 bounds_.size() == bounds.size() ? SCHEDULE_PAINT_SIZE_SAME : | |
| 287 SCHEDULE_PAINT_SIZE_CHANGED); | |
| 288 } | |
| 289 | |
| 290 gfx::Rect prev = bounds_; | |
| 291 bounds_ = bounds; | |
| 292 BoundsChanged(prev); | |
| 293 } | |
| 294 | |
| 295 void View::SetSize(const gfx::Size& size) { | |
| 296 SetBounds(x(), y(), size.width(), size.height()); | |
| 297 } | |
| 298 | |
| 299 void View::SetPosition(const gfx::Point& position) { | |
| 300 SetBounds(position.x(), position.y(), width(), height()); | |
| 301 } | |
| 302 | |
| 303 void View::SetX(int x) { | |
| 304 SetBounds(x, y(), width(), height()); | |
| 305 } | |
| 306 | |
| 307 void View::SetY(int y) { | |
| 308 SetBounds(x(), y, width(), height()); | |
| 309 } | |
| 310 | |
| 311 gfx::Rect View::GetContentsBounds() const { | |
| 312 gfx::Rect contents_bounds(GetLocalBounds()); | |
| 313 if (border_.get()) | |
| 314 contents_bounds.Inset(border_->GetInsets()); | |
| 315 return contents_bounds; | |
| 316 } | |
| 317 | |
| 318 gfx::Rect View::GetLocalBounds() const { | |
| 319 return gfx::Rect(size()); | |
| 320 } | |
| 321 | |
| 322 gfx::Rect View::GetLayerBoundsInPixel() const { | |
| 323 return layer()->GetTargetBounds(); | |
| 324 } | |
| 325 | |
| 326 gfx::Insets View::GetInsets() const { | |
| 327 return border_.get() ? border_->GetInsets() : gfx::Insets(); | |
| 328 } | |
| 329 | |
| 330 gfx::Rect View::GetVisibleBounds() const { | |
| 331 if (!IsDrawn()) | |
| 332 return gfx::Rect(); | |
| 333 gfx::Rect vis_bounds(GetLocalBounds()); | |
| 334 gfx::Rect ancestor_bounds; | |
| 335 const View* view = this; | |
| 336 gfx::Transform transform; | |
| 337 | |
| 338 while (view != NULL && !vis_bounds.IsEmpty()) { | |
| 339 transform.ConcatTransform(view->GetTransform()); | |
| 340 gfx::Transform translation; | |
| 341 translation.Translate(static_cast<float>(view->GetMirroredX()), | |
| 342 static_cast<float>(view->y())); | |
| 343 transform.ConcatTransform(translation); | |
| 344 | |
| 345 vis_bounds = view->ConvertRectToParent(vis_bounds); | |
| 346 const View* ancestor = view->parent_; | |
| 347 if (ancestor != NULL) { | |
| 348 ancestor_bounds.SetRect(0, 0, ancestor->width(), ancestor->height()); | |
| 349 vis_bounds.Intersect(ancestor_bounds); | |
| 350 } else if (!view->GetWidget()) { | |
| 351 // If the view has no Widget, we're not visible. Return an empty rect. | |
| 352 return gfx::Rect(); | |
| 353 } | |
| 354 view = ancestor; | |
| 355 } | |
| 356 if (vis_bounds.IsEmpty()) | |
| 357 return vis_bounds; | |
| 358 // Convert back to this views coordinate system. | |
| 359 gfx::RectF views_vis_bounds(vis_bounds); | |
| 360 transform.TransformRectReverse(&views_vis_bounds); | |
| 361 // Partially visible pixels should be considered visible. | |
| 362 return gfx::ToEnclosingRect(views_vis_bounds); | |
| 363 } | |
| 364 | |
| 365 gfx::Rect View::GetBoundsInScreen() const { | |
| 366 gfx::Point origin; | |
| 367 View::ConvertPointToScreen(this, &origin); | |
| 368 return gfx::Rect(origin, size()); | |
| 369 } | |
| 370 | |
| 371 gfx::Size View::GetPreferredSize() const { | |
| 372 if (layout_manager_.get()) | |
| 373 return layout_manager_->GetPreferredSize(this); | |
| 374 return gfx::Size(); | |
| 375 } | |
| 376 | |
| 377 int View::GetBaseline() const { | |
| 378 return -1; | |
| 379 } | |
| 380 | |
| 381 void View::SizeToPreferredSize() { | |
| 382 gfx::Size prefsize = GetPreferredSize(); | |
| 383 if ((prefsize.width() != width()) || (prefsize.height() != height())) | |
| 384 SetBounds(x(), y(), prefsize.width(), prefsize.height()); | |
| 385 } | |
| 386 | |
| 387 gfx::Size View::GetMinimumSize() const { | |
| 388 return GetPreferredSize(); | |
| 389 } | |
| 390 | |
| 391 gfx::Size View::GetMaximumSize() const { | |
| 392 return gfx::Size(); | |
| 393 } | |
| 394 | |
| 395 int View::GetHeightForWidth(int w) const { | |
| 396 if (layout_manager_.get()) | |
| 397 return layout_manager_->GetPreferredHeightForWidth(this, w); | |
| 398 return GetPreferredSize().height(); | |
| 399 } | |
| 400 | |
| 401 void View::SetVisible(bool visible) { | |
| 402 if (visible != visible_) { | |
| 403 // If the View is currently visible, schedule paint to refresh parent. | |
| 404 // TODO(beng): not sure we should be doing this if we have a layer. | |
| 405 if (visible_) | |
| 406 SchedulePaint(); | |
| 407 | |
| 408 visible_ = visible; | |
| 409 AdvanceFocusIfNecessary(); | |
| 410 | |
| 411 // Notify the parent. | |
| 412 if (parent_) | |
| 413 parent_->ChildVisibilityChanged(this); | |
| 414 | |
| 415 // This notifies all sub-views recursively. | |
| 416 PropagateVisibilityNotifications(this, visible_); | |
| 417 UpdateLayerVisibility(); | |
| 418 | |
| 419 // If we are newly visible, schedule paint. | |
| 420 if (visible_) { | |
| 421 SchedulePaint(); | |
| 422 } else { | |
| 423 // We're never painted when hidden, so no need to be in the BoundsTree. | |
| 424 BoundsTree* bounds_tree = GetBoundsTreeFromPaintRoot(); | |
| 425 if (bounds_tree) | |
| 426 RemoveRootBounds(bounds_tree); | |
| 427 } | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 bool View::IsDrawn() const { | |
| 432 return visible_ && parent_ ? parent_->IsDrawn() : false; | |
| 433 } | |
| 434 | |
| 435 void View::SetEnabled(bool enabled) { | |
| 436 if (enabled != enabled_) { | |
| 437 enabled_ = enabled; | |
| 438 AdvanceFocusIfNecessary(); | |
| 439 OnEnabledChanged(); | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 void View::OnEnabledChanged() { | |
| 444 SchedulePaint(); | |
| 445 } | |
| 446 | |
| 447 // Transformations ------------------------------------------------------------- | |
| 448 | |
| 449 gfx::Transform View::GetTransform() const { | |
| 450 return layer() ? layer()->transform() : gfx::Transform(); | |
| 451 } | |
| 452 | |
| 453 void View::SetTransform(const gfx::Transform& transform) { | |
| 454 if (transform.IsIdentity()) { | |
| 455 if (layer()) { | |
| 456 layer()->SetTransform(transform); | |
| 457 if (!paint_to_layer_) | |
| 458 DestroyLayer(); | |
| 459 } else { | |
| 460 // Nothing. | |
| 461 } | |
| 462 } else { | |
| 463 if (!layer()) | |
| 464 CreateLayer(); | |
| 465 layer()->SetTransform(transform); | |
| 466 layer()->ScheduleDraw(); | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 void View::SetPaintToLayer(bool paint_to_layer) { | |
| 471 if (paint_to_layer_ == paint_to_layer) | |
| 472 return; | |
| 473 | |
| 474 // If this is a change in state we will also need to update bounds trees. | |
| 475 if (paint_to_layer) { | |
| 476 // Gaining a layer means becoming a paint root. We must remove ourselves | |
| 477 // from our old paint root, if we had one. Traverse up view tree to find old | |
| 478 // paint root. | |
| 479 View* old_paint_root = parent_; | |
| 480 while (old_paint_root && !old_paint_root->IsPaintRoot()) | |
| 481 old_paint_root = old_paint_root->parent_; | |
| 482 | |
| 483 // Remove our and our children's bounds from the old tree. This will also | |
| 484 // mark all of our bounds as dirty. | |
| 485 if (old_paint_root && old_paint_root->bounds_tree_) | |
| 486 RemoveRootBounds(old_paint_root->bounds_tree_.get()); | |
| 487 | |
| 488 } else { | |
| 489 // Losing a layer means we are no longer a paint root, so delete our | |
| 490 // bounds tree and mark ourselves as dirty for future insertion into our | |
| 491 // new paint root's bounds tree. | |
| 492 bounds_tree_.reset(); | |
| 493 SetRootBoundsDirty(true); | |
| 494 } | |
| 495 | |
| 496 paint_to_layer_ = paint_to_layer; | |
| 497 if (paint_to_layer_ && !layer()) { | |
| 498 CreateLayer(); | |
| 499 } else if (!paint_to_layer_ && layer()) { | |
| 500 DestroyLayer(); | |
| 501 } | |
| 502 } | |
| 503 | |
| 504 // RTL positioning ------------------------------------------------------------- | |
| 505 | |
| 506 gfx::Rect View::GetMirroredBounds() const { | |
| 507 gfx::Rect bounds(bounds_); | |
| 508 bounds.set_x(GetMirroredX()); | |
| 509 return bounds; | |
| 510 } | |
| 511 | |
| 512 gfx::Point View::GetMirroredPosition() const { | |
| 513 return gfx::Point(GetMirroredX(), y()); | |
| 514 } | |
| 515 | |
| 516 int View::GetMirroredX() const { | |
| 517 return parent_ ? parent_->GetMirroredXForRect(bounds_) : x(); | |
| 518 } | |
| 519 | |
| 520 int View::GetMirroredXForRect(const gfx::Rect& bounds) const { | |
| 521 return base::i18n::IsRTL() ? | |
| 522 (width() - bounds.x() - bounds.width()) : bounds.x(); | |
| 523 } | |
| 524 | |
| 525 int View::GetMirroredXInView(int x) const { | |
| 526 return base::i18n::IsRTL() ? width() - x : x; | |
| 527 } | |
| 528 | |
| 529 int View::GetMirroredXWithWidthInView(int x, int w) const { | |
| 530 return base::i18n::IsRTL() ? width() - x - w : x; | |
| 531 } | |
| 532 | |
| 533 // Layout ---------------------------------------------------------------------- | |
| 534 | |
| 535 void View::Layout() { | |
| 536 needs_layout_ = false; | |
| 537 | |
| 538 // If we have a layout manager, let it handle the layout for us. | |
| 539 if (layout_manager_.get()) | |
| 540 layout_manager_->Layout(this); | |
| 541 | |
| 542 // Make sure to propagate the Layout() call to any children that haven't | |
| 543 // received it yet through the layout manager and need to be laid out. This | |
| 544 // is needed for the case when the child requires a layout but its bounds | |
| 545 // weren't changed by the layout manager. If there is no layout manager, we | |
| 546 // just propagate the Layout() call down the hierarchy, so whoever receives | |
| 547 // the call can take appropriate action. | |
| 548 for (int i = 0, count = child_count(); i < count; ++i) { | |
| 549 View* child = child_at(i); | |
| 550 if (child->needs_layout_ || !layout_manager_.get()) { | |
| 551 child->needs_layout_ = false; | |
| 552 child->Layout(); | |
| 553 } | |
| 554 } | |
| 555 } | |
| 556 | |
| 557 void View::InvalidateLayout() { | |
| 558 // Always invalidate up. This is needed to handle the case of us already being | |
| 559 // valid, but not our parent. | |
| 560 needs_layout_ = true; | |
| 561 if (parent_) | |
| 562 parent_->InvalidateLayout(); | |
| 563 } | |
| 564 | |
| 565 LayoutManager* View::GetLayoutManager() const { | |
| 566 return layout_manager_.get(); | |
| 567 } | |
| 568 | |
| 569 void View::SetLayoutManager(LayoutManager* layout_manager) { | |
| 570 if (layout_manager_.get()) | |
| 571 layout_manager_->Uninstalled(this); | |
| 572 | |
| 573 layout_manager_.reset(layout_manager); | |
| 574 if (layout_manager_.get()) | |
| 575 layout_manager_->Installed(this); | |
| 576 } | |
| 577 | |
| 578 void View::SnapLayerToPixelBoundary() { | |
| 579 if (!layer()) | |
| 580 return; | |
| 581 | |
| 582 if (snap_layer_to_pixel_boundary_ && layer()->parent() && | |
| 583 layer()->GetCompositor()) { | |
| 584 ui::SnapLayerToPhysicalPixelBoundary(layer()->parent(), layer()); | |
| 585 } else { | |
| 586 // Reset the offset. | |
| 587 layer()->SetSubpixelPositionOffset(gfx::Vector2dF()); | |
| 588 } | |
| 589 } | |
| 590 | |
| 591 // Attributes ------------------------------------------------------------------ | |
| 592 | |
| 593 const char* View::GetClassName() const { | |
| 594 return kViewClassName; | |
| 595 } | |
| 596 | |
| 597 const View* View::GetAncestorWithClassName(const std::string& name) const { | |
| 598 for (const View* view = this; view; view = view->parent_) { | |
| 599 if (!strcmp(view->GetClassName(), name.c_str())) | |
| 600 return view; | |
| 601 } | |
| 602 return NULL; | |
| 603 } | |
| 604 | |
| 605 View* View::GetAncestorWithClassName(const std::string& name) { | |
| 606 return const_cast<View*>(const_cast<const View*>(this)-> | |
| 607 GetAncestorWithClassName(name)); | |
| 608 } | |
| 609 | |
| 610 const View* View::GetViewByID(int id) const { | |
| 611 if (id == id_) | |
| 612 return const_cast<View*>(this); | |
| 613 | |
| 614 for (int i = 0, count = child_count(); i < count; ++i) { | |
| 615 const View* view = child_at(i)->GetViewByID(id); | |
| 616 if (view) | |
| 617 return view; | |
| 618 } | |
| 619 return NULL; | |
| 620 } | |
| 621 | |
| 622 View* View::GetViewByID(int id) { | |
| 623 return const_cast<View*>(const_cast<const View*>(this)->GetViewByID(id)); | |
| 624 } | |
| 625 | |
| 626 void View::SetGroup(int gid) { | |
| 627 // Don't change the group id once it's set. | |
| 628 DCHECK(group_ == -1 || group_ == gid); | |
| 629 group_ = gid; | |
| 630 } | |
| 631 | |
| 632 int View::GetGroup() const { | |
| 633 return group_; | |
| 634 } | |
| 635 | |
| 636 bool View::IsGroupFocusTraversable() const { | |
| 637 return true; | |
| 638 } | |
| 639 | |
| 640 void View::GetViewsInGroup(int group, Views* views) { | |
| 641 if (group_ == group) | |
| 642 views->push_back(this); | |
| 643 | |
| 644 for (int i = 0, count = child_count(); i < count; ++i) | |
| 645 child_at(i)->GetViewsInGroup(group, views); | |
| 646 } | |
| 647 | |
| 648 View* View::GetSelectedViewForGroup(int group) { | |
| 649 Views views; | |
| 650 GetWidget()->GetRootView()->GetViewsInGroup(group, &views); | |
| 651 return views.empty() ? NULL : views[0]; | |
| 652 } | |
| 653 | |
| 654 // Coordinate conversion ------------------------------------------------------- | |
| 655 | |
| 656 // static | |
| 657 void View::ConvertPointToTarget(const View* source, | |
| 658 const View* target, | |
| 659 gfx::Point* point) { | |
| 660 DCHECK(source); | |
| 661 DCHECK(target); | |
| 662 if (source == target) | |
| 663 return; | |
| 664 | |
| 665 const View* root = GetHierarchyRoot(target); | |
| 666 CHECK_EQ(GetHierarchyRoot(source), root); | |
| 667 | |
| 668 if (source != root) | |
| 669 source->ConvertPointForAncestor(root, point); | |
| 670 | |
| 671 if (target != root) | |
| 672 target->ConvertPointFromAncestor(root, point); | |
| 673 } | |
| 674 | |
| 675 // static | |
| 676 void View::ConvertRectToTarget(const View* source, | |
| 677 const View* target, | |
| 678 gfx::RectF* rect) { | |
| 679 DCHECK(source); | |
| 680 DCHECK(target); | |
| 681 if (source == target) | |
| 682 return; | |
| 683 | |
| 684 const View* root = GetHierarchyRoot(target); | |
| 685 CHECK_EQ(GetHierarchyRoot(source), root); | |
| 686 | |
| 687 if (source != root) | |
| 688 source->ConvertRectForAncestor(root, rect); | |
| 689 | |
| 690 if (target != root) | |
| 691 target->ConvertRectFromAncestor(root, rect); | |
| 692 } | |
| 693 | |
| 694 // static | |
| 695 void View::ConvertPointToWidget(const View* src, gfx::Point* p) { | |
| 696 DCHECK(src); | |
| 697 DCHECK(p); | |
| 698 | |
| 699 src->ConvertPointForAncestor(NULL, p); | |
| 700 } | |
| 701 | |
| 702 // static | |
| 703 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { | |
| 704 DCHECK(dest); | |
| 705 DCHECK(p); | |
| 706 | |
| 707 dest->ConvertPointFromAncestor(NULL, p); | |
| 708 } | |
| 709 | |
| 710 // static | |
| 711 void View::ConvertPointToScreen(const View* src, gfx::Point* p) { | |
| 712 DCHECK(src); | |
| 713 DCHECK(p); | |
| 714 | |
| 715 // If the view is not connected to a tree, there's nothing we can do. | |
| 716 const Widget* widget = src->GetWidget(); | |
| 717 if (widget) { | |
| 718 ConvertPointToWidget(src, p); | |
| 719 *p += widget->GetClientAreaBoundsInScreen().OffsetFromOrigin(); | |
| 720 } | |
| 721 } | |
| 722 | |
| 723 // static | |
| 724 void View::ConvertPointFromScreen(const View* dst, gfx::Point* p) { | |
| 725 DCHECK(dst); | |
| 726 DCHECK(p); | |
| 727 | |
| 728 const views::Widget* widget = dst->GetWidget(); | |
| 729 if (!widget) | |
| 730 return; | |
| 731 *p -= widget->GetClientAreaBoundsInScreen().OffsetFromOrigin(); | |
| 732 views::View::ConvertPointFromWidget(dst, p); | |
| 733 } | |
| 734 | |
| 735 gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const { | |
| 736 gfx::RectF x_rect = rect; | |
| 737 GetTransform().TransformRect(&x_rect); | |
| 738 x_rect.Offset(GetMirroredPosition().OffsetFromOrigin()); | |
| 739 // Pixels we partially occupy in the parent should be included. | |
| 740 return gfx::ToEnclosingRect(x_rect); | |
| 741 } | |
| 742 | |
| 743 gfx::Rect View::ConvertRectToWidget(const gfx::Rect& rect) const { | |
| 744 gfx::Rect x_rect = rect; | |
| 745 for (const View* v = this; v; v = v->parent_) | |
| 746 x_rect = v->ConvertRectToParent(x_rect); | |
| 747 return x_rect; | |
| 748 } | |
| 749 | |
| 750 // Painting -------------------------------------------------------------------- | |
| 751 | |
| 752 void View::SchedulePaint() { | |
| 753 SchedulePaintInRect(GetLocalBounds()); | |
| 754 } | |
| 755 | |
| 756 void View::SchedulePaintInRect(const gfx::Rect& rect) { | |
| 757 if (!visible_) | |
| 758 return; | |
| 759 | |
| 760 if (layer()) { | |
| 761 layer()->SchedulePaint(rect); | |
| 762 } else if (parent_) { | |
| 763 // Translate the requested paint rect to the parent's coordinate system | |
| 764 // then pass this notification up to the parent. | |
| 765 parent_->SchedulePaintInRect(ConvertRectToParent(rect)); | |
| 766 } | |
| 767 } | |
| 768 | |
| 769 void View::Paint(gfx::Canvas* canvas, const CullSet& cull_set) { | |
| 770 // The cull_set may allow us to skip painting without canvas construction or | |
| 771 // even canvas rect intersection. | |
| 772 if (cull_set.ShouldPaint(this)) { | |
| 773 TRACE_EVENT1("views", "View::Paint", "class", GetClassName()); | |
| 774 | |
| 775 gfx::ScopedCanvas scoped_canvas(canvas); | |
| 776 | |
| 777 // Paint this View and its children, setting the clip rect to the bounds | |
| 778 // of this View and translating the origin to the local bounds' top left | |
| 779 // point. | |
| 780 // | |
| 781 // Note that the X (or left) position we pass to ClipRectInt takes into | |
| 782 // consideration whether or not the view uses a right-to-left layout so that | |
| 783 // we paint our view in its mirrored position if need be. | |
| 784 gfx::Rect clip_rect = bounds(); | |
| 785 clip_rect.Inset(clip_insets_); | |
| 786 if (parent_) | |
| 787 clip_rect.set_x(parent_->GetMirroredXForRect(clip_rect)); | |
| 788 canvas->ClipRect(clip_rect); | |
| 789 if (canvas->IsClipEmpty()) | |
| 790 return; | |
| 791 | |
| 792 // Non-empty clip, translate the graphics such that 0,0 corresponds to where | |
| 793 // this view is located (related to its parent). | |
| 794 canvas->Translate(GetMirroredPosition().OffsetFromOrigin()); | |
| 795 canvas->Transform(GetTransform()); | |
| 796 | |
| 797 // If we are a paint root, we need to construct our own CullSet object for | |
| 798 // propagation to our children. | |
| 799 if (IsPaintRoot()) { | |
| 800 if (!bounds_tree_) | |
| 801 bounds_tree_.reset(new BoundsTree(2, 5)); | |
| 802 | |
| 803 // Recompute our bounds tree as needed. | |
| 804 UpdateRootBounds(bounds_tree_.get(), gfx::Vector2d()); | |
| 805 | |
| 806 // Grab the clip rect from the supplied canvas to use as the query rect. | |
| 807 gfx::Rect canvas_bounds; | |
| 808 if (!canvas->GetClipBounds(&canvas_bounds)) { | |
| 809 NOTREACHED() << "Failed to get clip bounds from the canvas!"; | |
| 810 return; | |
| 811 } | |
| 812 | |
| 813 // Now query our bounds_tree_ for a set of damaged views that intersect | |
| 814 // our canvas bounds. | |
| 815 scoped_ptr<base::hash_set<intptr_t> > damaged_views( | |
| 816 new base::hash_set<intptr_t>()); | |
| 817 bounds_tree_->AppendIntersectingRecords( | |
| 818 canvas_bounds, damaged_views.get()); | |
| 819 // Construct a CullSet to wrap the damaged views set, it will delete it | |
| 820 // for us on scope exit. | |
| 821 CullSet paint_root_cull_set(damaged_views.Pass()); | |
| 822 // Paint all descendents using our new cull set. | |
| 823 PaintCommon(canvas, paint_root_cull_set); | |
| 824 } else { | |
| 825 // Not a paint root, so we can proceed as normal. | |
| 826 PaintCommon(canvas, cull_set); | |
| 827 } | |
| 828 } | |
| 829 } | |
| 830 | |
| 831 void View::set_background(Background* b) { | |
| 832 background_.reset(b); | |
| 833 } | |
| 834 | |
| 835 void View::SetBorder(scoped_ptr<Border> b) { border_ = b.Pass(); } | |
| 836 | |
| 837 ui::ThemeProvider* View::GetThemeProvider() const { | |
| 838 const Widget* widget = GetWidget(); | |
| 839 return widget ? widget->GetThemeProvider() : NULL; | |
| 840 } | |
| 841 | |
| 842 const ui::NativeTheme* View::GetNativeTheme() const { | |
| 843 const Widget* widget = GetWidget(); | |
| 844 return widget ? widget->GetNativeTheme() : ui::NativeTheme::instance(); | |
| 845 } | |
| 846 | |
| 847 // Input ----------------------------------------------------------------------- | |
| 848 | |
| 849 View* View::GetEventHandlerForPoint(const gfx::Point& point) { | |
| 850 return GetEventHandlerForRect(gfx::Rect(point, gfx::Size(1, 1))); | |
| 851 } | |
| 852 | |
| 853 View* View::GetEventHandlerForRect(const gfx::Rect& rect) { | |
| 854 return GetEffectiveViewTargeter()->TargetForRect(this, rect); | |
| 855 } | |
| 856 | |
| 857 bool View::CanProcessEventsWithinSubtree() const { | |
| 858 return true; | |
| 859 } | |
| 860 | |
| 861 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) { | |
| 862 // TODO(tdanderson): Move this implementation into ViewTargetDelegate. | |
| 863 if (!HitTestPoint(point) || !CanProcessEventsWithinSubtree()) | |
| 864 return NULL; | |
| 865 | |
| 866 // Walk the child Views recursively looking for the View that most | |
| 867 // tightly encloses the specified point. | |
| 868 for (int i = child_count() - 1; i >= 0; --i) { | |
| 869 View* child = child_at(i); | |
| 870 if (!child->visible()) | |
| 871 continue; | |
| 872 | |
| 873 gfx::Point point_in_child_coords(point); | |
| 874 ConvertPointToTarget(this, child, &point_in_child_coords); | |
| 875 View* handler = child->GetTooltipHandlerForPoint(point_in_child_coords); | |
| 876 if (handler) | |
| 877 return handler; | |
| 878 } | |
| 879 return this; | |
| 880 } | |
| 881 | |
| 882 gfx::NativeCursor View::GetCursor(const ui::MouseEvent& event) { | |
| 883 #if defined(OS_WIN) | |
| 884 static ui::Cursor arrow; | |
| 885 if (!arrow.platform()) | |
| 886 arrow.SetPlatformCursor(LoadCursor(NULL, IDC_ARROW)); | |
| 887 return arrow; | |
| 888 #else | |
| 889 return gfx::kNullCursor; | |
| 890 #endif | |
| 891 } | |
| 892 | |
| 893 bool View::HitTestPoint(const gfx::Point& point) const { | |
| 894 return HitTestRect(gfx::Rect(point, gfx::Size(1, 1))); | |
| 895 } | |
| 896 | |
| 897 bool View::HitTestRect(const gfx::Rect& rect) const { | |
| 898 return GetEffectiveViewTargeter()->DoesIntersectRect(this, rect); | |
| 899 } | |
| 900 | |
| 901 bool View::IsMouseHovered() { | |
| 902 // If we haven't yet been placed in an onscreen view hierarchy, we can't be | |
| 903 // hovered. | |
| 904 if (!GetWidget()) | |
| 905 return false; | |
| 906 | |
| 907 // If mouse events are disabled, then the mouse cursor is invisible and | |
| 908 // is therefore not hovering over this button. | |
| 909 if (!GetWidget()->IsMouseEventsEnabled()) | |
| 910 return false; | |
| 911 | |
| 912 gfx::Point cursor_pos(gfx::Screen::GetScreenFor( | |
| 913 GetWidget()->GetNativeView())->GetCursorScreenPoint()); | |
| 914 ConvertPointFromScreen(this, &cursor_pos); | |
| 915 return HitTestPoint(cursor_pos); | |
| 916 } | |
| 917 | |
| 918 bool View::OnMousePressed(const ui::MouseEvent& event) { | |
| 919 return false; | |
| 920 } | |
| 921 | |
| 922 bool View::OnMouseDragged(const ui::MouseEvent& event) { | |
| 923 return false; | |
| 924 } | |
| 925 | |
| 926 void View::OnMouseReleased(const ui::MouseEvent& event) { | |
| 927 } | |
| 928 | |
| 929 void View::OnMouseCaptureLost() { | |
| 930 } | |
| 931 | |
| 932 void View::OnMouseMoved(const ui::MouseEvent& event) { | |
| 933 } | |
| 934 | |
| 935 void View::OnMouseEntered(const ui::MouseEvent& event) { | |
| 936 } | |
| 937 | |
| 938 void View::OnMouseExited(const ui::MouseEvent& event) { | |
| 939 } | |
| 940 | |
| 941 void View::SetMouseHandler(View* new_mouse_handler) { | |
| 942 // |new_mouse_handler| may be NULL. | |
| 943 if (parent_) | |
| 944 parent_->SetMouseHandler(new_mouse_handler); | |
| 945 } | |
| 946 | |
| 947 bool View::OnKeyPressed(const ui::KeyEvent& event) { | |
| 948 return false; | |
| 949 } | |
| 950 | |
| 951 bool View::OnKeyReleased(const ui::KeyEvent& event) { | |
| 952 return false; | |
| 953 } | |
| 954 | |
| 955 bool View::OnMouseWheel(const ui::MouseWheelEvent& event) { | |
| 956 return false; | |
| 957 } | |
| 958 | |
| 959 void View::OnKeyEvent(ui::KeyEvent* event) { | |
| 960 bool consumed = (event->type() == ui::ET_KEY_PRESSED) ? OnKeyPressed(*event) : | |
| 961 OnKeyReleased(*event); | |
| 962 if (consumed) | |
| 963 event->StopPropagation(); | |
| 964 } | |
| 965 | |
| 966 void View::OnMouseEvent(ui::MouseEvent* event) { | |
| 967 switch (event->type()) { | |
| 968 case ui::ET_MOUSE_PRESSED: | |
| 969 if (ProcessMousePressed(*event)) | |
| 970 event->SetHandled(); | |
| 971 return; | |
| 972 | |
| 973 case ui::ET_MOUSE_MOVED: | |
| 974 if ((event->flags() & (ui::EF_LEFT_MOUSE_BUTTON | | |
| 975 ui::EF_RIGHT_MOUSE_BUTTON | | |
| 976 ui::EF_MIDDLE_MOUSE_BUTTON)) == 0) { | |
| 977 OnMouseMoved(*event); | |
| 978 return; | |
| 979 } | |
| 980 // FALL-THROUGH | |
| 981 case ui::ET_MOUSE_DRAGGED: | |
| 982 if (ProcessMouseDragged(*event)) | |
| 983 event->SetHandled(); | |
| 984 return; | |
| 985 | |
| 986 case ui::ET_MOUSE_RELEASED: | |
| 987 ProcessMouseReleased(*event); | |
| 988 return; | |
| 989 | |
| 990 case ui::ET_MOUSEWHEEL: | |
| 991 if (OnMouseWheel(*static_cast<ui::MouseWheelEvent*>(event))) | |
| 992 event->SetHandled(); | |
| 993 break; | |
| 994 | |
| 995 case ui::ET_MOUSE_ENTERED: | |
| 996 if (event->flags() & ui::EF_TOUCH_ACCESSIBILITY) | |
| 997 NotifyAccessibilityEvent(ui::AX_EVENT_HOVER, true); | |
| 998 OnMouseEntered(*event); | |
| 999 break; | |
| 1000 | |
| 1001 case ui::ET_MOUSE_EXITED: | |
| 1002 OnMouseExited(*event); | |
| 1003 break; | |
| 1004 | |
| 1005 default: | |
| 1006 return; | |
| 1007 } | |
| 1008 } | |
| 1009 | |
| 1010 void View::OnScrollEvent(ui::ScrollEvent* event) { | |
| 1011 } | |
| 1012 | |
| 1013 void View::OnTouchEvent(ui::TouchEvent* event) { | |
| 1014 NOTREACHED() << "Views should not receive touch events."; | |
| 1015 } | |
| 1016 | |
| 1017 void View::OnGestureEvent(ui::GestureEvent* event) { | |
| 1018 } | |
| 1019 | |
| 1020 ui::TextInputClient* View::GetTextInputClient() { | |
| 1021 return NULL; | |
| 1022 } | |
| 1023 | |
| 1024 InputMethod* View::GetInputMethod() { | |
| 1025 Widget* widget = GetWidget(); | |
| 1026 return widget ? widget->GetInputMethod() : NULL; | |
| 1027 } | |
| 1028 | |
| 1029 const InputMethod* View::GetInputMethod() const { | |
| 1030 const Widget* widget = GetWidget(); | |
| 1031 return widget ? widget->GetInputMethod() : NULL; | |
| 1032 } | |
| 1033 | |
| 1034 scoped_ptr<ViewTargeter> | |
| 1035 View::SetEventTargeter(scoped_ptr<ViewTargeter> targeter) { | |
| 1036 scoped_ptr<ViewTargeter> old_targeter = targeter_.Pass(); | |
| 1037 targeter_ = targeter.Pass(); | |
| 1038 return old_targeter.Pass(); | |
| 1039 } | |
| 1040 | |
| 1041 ViewTargeter* View::GetEffectiveViewTargeter() const { | |
| 1042 DCHECK(GetWidget()); | |
| 1043 ViewTargeter* view_targeter = targeter(); | |
| 1044 if (!view_targeter) | |
| 1045 view_targeter = GetWidget()->GetRootView()->targeter(); | |
| 1046 CHECK(view_targeter); | |
| 1047 return view_targeter; | |
| 1048 } | |
| 1049 | |
| 1050 bool View::CanAcceptEvent(const ui::Event& event) { | |
| 1051 return IsDrawn(); | |
| 1052 } | |
| 1053 | |
| 1054 ui::EventTarget* View::GetParentTarget() { | |
| 1055 return parent_; | |
| 1056 } | |
| 1057 | |
| 1058 scoped_ptr<ui::EventTargetIterator> View::GetChildIterator() { | |
| 1059 return scoped_ptr<ui::EventTargetIterator>( | |
| 1060 new ui::EventTargetIteratorImpl<View>(children_)); | |
| 1061 } | |
| 1062 | |
| 1063 ui::EventTargeter* View::GetEventTargeter() { | |
| 1064 return targeter_.get(); | |
| 1065 } | |
| 1066 | |
| 1067 void View::ConvertEventToTarget(ui::EventTarget* target, | |
| 1068 ui::LocatedEvent* event) { | |
| 1069 event->ConvertLocationToTarget(this, static_cast<View*>(target)); | |
| 1070 } | |
| 1071 | |
| 1072 // Accelerators ---------------------------------------------------------------- | |
| 1073 | |
| 1074 void View::AddAccelerator(const ui::Accelerator& accelerator) { | |
| 1075 if (!accelerators_.get()) | |
| 1076 accelerators_.reset(new std::vector<ui::Accelerator>()); | |
| 1077 | |
| 1078 if (std::find(accelerators_->begin(), accelerators_->end(), accelerator) == | |
| 1079 accelerators_->end()) { | |
| 1080 accelerators_->push_back(accelerator); | |
| 1081 } | |
| 1082 RegisterPendingAccelerators(); | |
| 1083 } | |
| 1084 | |
| 1085 void View::RemoveAccelerator(const ui::Accelerator& accelerator) { | |
| 1086 if (!accelerators_.get()) { | |
| 1087 NOTREACHED() << "Removing non-existing accelerator"; | |
| 1088 return; | |
| 1089 } | |
| 1090 | |
| 1091 std::vector<ui::Accelerator>::iterator i( | |
| 1092 std::find(accelerators_->begin(), accelerators_->end(), accelerator)); | |
| 1093 if (i == accelerators_->end()) { | |
| 1094 NOTREACHED() << "Removing non-existing accelerator"; | |
| 1095 return; | |
| 1096 } | |
| 1097 | |
| 1098 size_t index = i - accelerators_->begin(); | |
| 1099 accelerators_->erase(i); | |
| 1100 if (index >= registered_accelerator_count_) { | |
| 1101 // The accelerator is not registered to FocusManager. | |
| 1102 return; | |
| 1103 } | |
| 1104 --registered_accelerator_count_; | |
| 1105 | |
| 1106 // Providing we are attached to a Widget and registered with a focus manager, | |
| 1107 // we should de-register from that focus manager now. | |
| 1108 if (GetWidget() && accelerator_focus_manager_) | |
| 1109 accelerator_focus_manager_->UnregisterAccelerator(accelerator, this); | |
| 1110 } | |
| 1111 | |
| 1112 void View::ResetAccelerators() { | |
| 1113 if (accelerators_.get()) | |
| 1114 UnregisterAccelerators(false); | |
| 1115 } | |
| 1116 | |
| 1117 bool View::AcceleratorPressed(const ui::Accelerator& accelerator) { | |
| 1118 return false; | |
| 1119 } | |
| 1120 | |
| 1121 bool View::CanHandleAccelerators() const { | |
| 1122 return enabled() && IsDrawn() && GetWidget() && GetWidget()->IsVisible(); | |
| 1123 } | |
| 1124 | |
| 1125 // Focus ----------------------------------------------------------------------- | |
| 1126 | |
| 1127 bool View::HasFocus() const { | |
| 1128 const FocusManager* focus_manager = GetFocusManager(); | |
| 1129 return focus_manager && (focus_manager->GetFocusedView() == this); | |
| 1130 } | |
| 1131 | |
| 1132 View* View::GetNextFocusableView() { | |
| 1133 return next_focusable_view_; | |
| 1134 } | |
| 1135 | |
| 1136 const View* View::GetNextFocusableView() const { | |
| 1137 return next_focusable_view_; | |
| 1138 } | |
| 1139 | |
| 1140 View* View::GetPreviousFocusableView() { | |
| 1141 return previous_focusable_view_; | |
| 1142 } | |
| 1143 | |
| 1144 void View::SetNextFocusableView(View* view) { | |
| 1145 if (view) | |
| 1146 view->previous_focusable_view_ = this; | |
| 1147 next_focusable_view_ = view; | |
| 1148 } | |
| 1149 | |
| 1150 void View::SetFocusable(bool focusable) { | |
| 1151 if (focusable_ == focusable) | |
| 1152 return; | |
| 1153 | |
| 1154 focusable_ = focusable; | |
| 1155 AdvanceFocusIfNecessary(); | |
| 1156 } | |
| 1157 | |
| 1158 bool View::IsFocusable() const { | |
| 1159 return focusable_ && enabled_ && IsDrawn(); | |
| 1160 } | |
| 1161 | |
| 1162 bool View::IsAccessibilityFocusable() const { | |
| 1163 return (focusable_ || accessibility_focusable_) && enabled_ && IsDrawn(); | |
| 1164 } | |
| 1165 | |
| 1166 void View::SetAccessibilityFocusable(bool accessibility_focusable) { | |
| 1167 if (accessibility_focusable_ == accessibility_focusable) | |
| 1168 return; | |
| 1169 | |
| 1170 accessibility_focusable_ = accessibility_focusable; | |
| 1171 AdvanceFocusIfNecessary(); | |
| 1172 } | |
| 1173 | |
| 1174 FocusManager* View::GetFocusManager() { | |
| 1175 Widget* widget = GetWidget(); | |
| 1176 return widget ? widget->GetFocusManager() : NULL; | |
| 1177 } | |
| 1178 | |
| 1179 const FocusManager* View::GetFocusManager() const { | |
| 1180 const Widget* widget = GetWidget(); | |
| 1181 return widget ? widget->GetFocusManager() : NULL; | |
| 1182 } | |
| 1183 | |
| 1184 void View::RequestFocus() { | |
| 1185 FocusManager* focus_manager = GetFocusManager(); | |
| 1186 if (focus_manager && IsFocusable()) | |
| 1187 focus_manager->SetFocusedView(this); | |
| 1188 } | |
| 1189 | |
| 1190 bool View::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) { | |
| 1191 return false; | |
| 1192 } | |
| 1193 | |
| 1194 FocusTraversable* View::GetFocusTraversable() { | |
| 1195 return NULL; | |
| 1196 } | |
| 1197 | |
| 1198 FocusTraversable* View::GetPaneFocusTraversable() { | |
| 1199 return NULL; | |
| 1200 } | |
| 1201 | |
| 1202 // Tooltips -------------------------------------------------------------------- | |
| 1203 | |
| 1204 bool View::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const { | |
| 1205 return false; | |
| 1206 } | |
| 1207 | |
| 1208 bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) const { | |
| 1209 return false; | |
| 1210 } | |
| 1211 | |
| 1212 // Context menus --------------------------------------------------------------- | |
| 1213 | |
| 1214 void View::ShowContextMenu(const gfx::Point& p, | |
| 1215 ui::MenuSourceType source_type) { | |
| 1216 if (!context_menu_controller_) | |
| 1217 return; | |
| 1218 | |
| 1219 context_menu_controller_->ShowContextMenuForView(this, p, source_type); | |
| 1220 } | |
| 1221 | |
| 1222 // static | |
| 1223 bool View::ShouldShowContextMenuOnMousePress() { | |
| 1224 return kContextMenuOnMousePress; | |
| 1225 } | |
| 1226 | |
| 1227 // Drag and drop --------------------------------------------------------------- | |
| 1228 | |
| 1229 bool View::GetDropFormats( | |
| 1230 int* formats, | |
| 1231 std::set<OSExchangeData::CustomFormat>* custom_formats) { | |
| 1232 return false; | |
| 1233 } | |
| 1234 | |
| 1235 bool View::AreDropTypesRequired() { | |
| 1236 return false; | |
| 1237 } | |
| 1238 | |
| 1239 bool View::CanDrop(const OSExchangeData& data) { | |
| 1240 // TODO(sky): when I finish up migration, this should default to true. | |
| 1241 return false; | |
| 1242 } | |
| 1243 | |
| 1244 void View::OnDragEntered(const ui::DropTargetEvent& event) { | |
| 1245 } | |
| 1246 | |
| 1247 int View::OnDragUpdated(const ui::DropTargetEvent& event) { | |
| 1248 return ui::DragDropTypes::DRAG_NONE; | |
| 1249 } | |
| 1250 | |
| 1251 void View::OnDragExited() { | |
| 1252 } | |
| 1253 | |
| 1254 int View::OnPerformDrop(const ui::DropTargetEvent& event) { | |
| 1255 return ui::DragDropTypes::DRAG_NONE; | |
| 1256 } | |
| 1257 | |
| 1258 void View::OnDragDone() { | |
| 1259 } | |
| 1260 | |
| 1261 // static | |
| 1262 bool View::ExceededDragThreshold(const gfx::Vector2d& delta) { | |
| 1263 return (abs(delta.x()) > GetHorizontalDragThreshold() || | |
| 1264 abs(delta.y()) > GetVerticalDragThreshold()); | |
| 1265 } | |
| 1266 | |
| 1267 // Accessibility---------------------------------------------------------------- | |
| 1268 | |
| 1269 gfx::NativeViewAccessible View::GetNativeViewAccessible() { | |
| 1270 if (!native_view_accessibility_) | |
| 1271 native_view_accessibility_ = NativeViewAccessibility::Create(this); | |
| 1272 if (native_view_accessibility_) | |
| 1273 return native_view_accessibility_->GetNativeObject(); | |
| 1274 return NULL; | |
| 1275 } | |
| 1276 | |
| 1277 void View::NotifyAccessibilityEvent( | |
| 1278 ui::AXEvent event_type, | |
| 1279 bool send_native_event) { | |
| 1280 if (ViewsDelegate::views_delegate) | |
| 1281 ViewsDelegate::views_delegate->NotifyAccessibilityEvent(this, event_type); | |
| 1282 | |
| 1283 if (send_native_event && GetWidget()) { | |
| 1284 if (!native_view_accessibility_) | |
| 1285 native_view_accessibility_ = NativeViewAccessibility::Create(this); | |
| 1286 if (native_view_accessibility_) | |
| 1287 native_view_accessibility_->NotifyAccessibilityEvent(event_type); | |
| 1288 } | |
| 1289 } | |
| 1290 | |
| 1291 // Scrolling ------------------------------------------------------------------- | |
| 1292 | |
| 1293 void View::ScrollRectToVisible(const gfx::Rect& rect) { | |
| 1294 // We must take RTL UI mirroring into account when adjusting the position of | |
| 1295 // the region. | |
| 1296 if (parent_) { | |
| 1297 gfx::Rect scroll_rect(rect); | |
| 1298 scroll_rect.Offset(GetMirroredX(), y()); | |
| 1299 parent_->ScrollRectToVisible(scroll_rect); | |
| 1300 } | |
| 1301 } | |
| 1302 | |
| 1303 int View::GetPageScrollIncrement(ScrollView* scroll_view, | |
| 1304 bool is_horizontal, bool is_positive) { | |
| 1305 return 0; | |
| 1306 } | |
| 1307 | |
| 1308 int View::GetLineScrollIncrement(ScrollView* scroll_view, | |
| 1309 bool is_horizontal, bool is_positive) { | |
| 1310 return 0; | |
| 1311 } | |
| 1312 | |
| 1313 //////////////////////////////////////////////////////////////////////////////// | |
| 1314 // View, protected: | |
| 1315 | |
| 1316 // Size and disposition -------------------------------------------------------- | |
| 1317 | |
| 1318 void View::OnBoundsChanged(const gfx::Rect& previous_bounds) { | |
| 1319 } | |
| 1320 | |
| 1321 void View::PreferredSizeChanged() { | |
| 1322 InvalidateLayout(); | |
| 1323 if (parent_) | |
| 1324 parent_->ChildPreferredSizeChanged(this); | |
| 1325 } | |
| 1326 | |
| 1327 bool View::GetNeedsNotificationWhenVisibleBoundsChange() const { | |
| 1328 return false; | |
| 1329 } | |
| 1330 | |
| 1331 void View::OnVisibleBoundsChanged() { | |
| 1332 } | |
| 1333 | |
| 1334 // Tree operations ------------------------------------------------------------- | |
| 1335 | |
| 1336 void View::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { | |
| 1337 } | |
| 1338 | |
| 1339 void View::VisibilityChanged(View* starting_from, bool is_visible) { | |
| 1340 } | |
| 1341 | |
| 1342 void View::NativeViewHierarchyChanged() { | |
| 1343 FocusManager* focus_manager = GetFocusManager(); | |
| 1344 if (accelerator_focus_manager_ != focus_manager) { | |
| 1345 UnregisterAccelerators(true); | |
| 1346 | |
| 1347 if (focus_manager) | |
| 1348 RegisterPendingAccelerators(); | |
| 1349 } | |
| 1350 } | |
| 1351 | |
| 1352 // Painting -------------------------------------------------------------------- | |
| 1353 | |
| 1354 void View::PaintChildren(gfx::Canvas* canvas, const CullSet& cull_set) { | |
| 1355 TRACE_EVENT1("views", "View::PaintChildren", "class", GetClassName()); | |
| 1356 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1357 if (!child_at(i)->layer()) | |
| 1358 child_at(i)->Paint(canvas, cull_set); | |
| 1359 } | |
| 1360 | |
| 1361 void View::OnPaint(gfx::Canvas* canvas) { | |
| 1362 TRACE_EVENT1("views", "View::OnPaint", "class", GetClassName()); | |
| 1363 OnPaintBackground(canvas); | |
| 1364 OnPaintBorder(canvas); | |
| 1365 } | |
| 1366 | |
| 1367 void View::OnPaintBackground(gfx::Canvas* canvas) { | |
| 1368 if (background_.get()) { | |
| 1369 TRACE_EVENT2("views", "View::OnPaintBackground", | |
| 1370 "width", canvas->sk_canvas()->getDevice()->width(), | |
| 1371 "height", canvas->sk_canvas()->getDevice()->height()); | |
| 1372 background_->Paint(canvas, this); | |
| 1373 } | |
| 1374 } | |
| 1375 | |
| 1376 void View::OnPaintBorder(gfx::Canvas* canvas) { | |
| 1377 if (border_.get()) { | |
| 1378 TRACE_EVENT2("views", "View::OnPaintBorder", | |
| 1379 "width", canvas->sk_canvas()->getDevice()->width(), | |
| 1380 "height", canvas->sk_canvas()->getDevice()->height()); | |
| 1381 border_->Paint(*this, canvas); | |
| 1382 } | |
| 1383 } | |
| 1384 | |
| 1385 bool View::IsPaintRoot() { | |
| 1386 return paint_to_layer_ || !parent_; | |
| 1387 } | |
| 1388 | |
| 1389 // Accelerated Painting -------------------------------------------------------- | |
| 1390 | |
| 1391 void View::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { | |
| 1392 // This method should not have the side-effect of creating the layer. | |
| 1393 if (layer()) | |
| 1394 layer()->SetFillsBoundsOpaquely(fills_bounds_opaquely); | |
| 1395 } | |
| 1396 | |
| 1397 gfx::Vector2d View::CalculateOffsetToAncestorWithLayer( | |
| 1398 ui::Layer** layer_parent) { | |
| 1399 if (layer()) { | |
| 1400 if (layer_parent) | |
| 1401 *layer_parent = layer(); | |
| 1402 return gfx::Vector2d(); | |
| 1403 } | |
| 1404 if (!parent_) | |
| 1405 return gfx::Vector2d(); | |
| 1406 | |
| 1407 return gfx::Vector2d(GetMirroredX(), y()) + | |
| 1408 parent_->CalculateOffsetToAncestorWithLayer(layer_parent); | |
| 1409 } | |
| 1410 | |
| 1411 void View::UpdateParentLayer() { | |
| 1412 if (!layer()) | |
| 1413 return; | |
| 1414 | |
| 1415 ui::Layer* parent_layer = NULL; | |
| 1416 gfx::Vector2d offset(GetMirroredX(), y()); | |
| 1417 | |
| 1418 if (parent_) | |
| 1419 offset += parent_->CalculateOffsetToAncestorWithLayer(&parent_layer); | |
| 1420 | |
| 1421 ReparentLayer(offset, parent_layer); | |
| 1422 } | |
| 1423 | |
| 1424 void View::MoveLayerToParent(ui::Layer* parent_layer, | |
| 1425 const gfx::Point& point) { | |
| 1426 gfx::Point local_point(point); | |
| 1427 if (parent_layer != layer()) | |
| 1428 local_point.Offset(GetMirroredX(), y()); | |
| 1429 if (layer() && parent_layer != layer()) { | |
| 1430 parent_layer->Add(layer()); | |
| 1431 SetLayerBounds(gfx::Rect(local_point.x(), local_point.y(), | |
| 1432 width(), height())); | |
| 1433 } else { | |
| 1434 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1435 child_at(i)->MoveLayerToParent(parent_layer, local_point); | |
| 1436 } | |
| 1437 } | |
| 1438 | |
| 1439 void View::UpdateLayerVisibility() { | |
| 1440 bool visible = visible_; | |
| 1441 for (const View* v = parent_; visible && v && !v->layer(); v = v->parent_) | |
| 1442 visible = v->visible(); | |
| 1443 | |
| 1444 UpdateChildLayerVisibility(visible); | |
| 1445 } | |
| 1446 | |
| 1447 void View::UpdateChildLayerVisibility(bool ancestor_visible) { | |
| 1448 if (layer()) { | |
| 1449 layer()->SetVisible(ancestor_visible && visible_); | |
| 1450 } else { | |
| 1451 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1452 child_at(i)->UpdateChildLayerVisibility(ancestor_visible && visible_); | |
| 1453 } | |
| 1454 } | |
| 1455 | |
| 1456 void View::UpdateChildLayerBounds(const gfx::Vector2d& offset) { | |
| 1457 if (layer()) { | |
| 1458 SetLayerBounds(GetLocalBounds() + offset); | |
| 1459 } else { | |
| 1460 for (int i = 0, count = child_count(); i < count; ++i) { | |
| 1461 View* child = child_at(i); | |
| 1462 child->UpdateChildLayerBounds( | |
| 1463 offset + gfx::Vector2d(child->GetMirroredX(), child->y())); | |
| 1464 } | |
| 1465 } | |
| 1466 } | |
| 1467 | |
| 1468 void View::OnPaintLayer(gfx::Canvas* canvas) { | |
| 1469 if (!layer() || !layer()->fills_bounds_opaquely()) | |
| 1470 canvas->DrawColor(SK_ColorBLACK, SkXfermode::kClear_Mode); | |
| 1471 PaintCommon(canvas, CullSet()); | |
| 1472 } | |
| 1473 | |
| 1474 void View::OnDelegatedFrameDamage( | |
| 1475 const gfx::Rect& damage_rect_in_dip) { | |
| 1476 } | |
| 1477 | |
| 1478 void View::OnDeviceScaleFactorChanged(float device_scale_factor) { | |
| 1479 snap_layer_to_pixel_boundary_ = | |
| 1480 (device_scale_factor - std::floor(device_scale_factor)) != 0.0f; | |
| 1481 SnapLayerToPixelBoundary(); | |
| 1482 // Repainting with new scale factor will paint the content at the right scale. | |
| 1483 } | |
| 1484 | |
| 1485 base::Closure View::PrepareForLayerBoundsChange() { | |
| 1486 return base::Closure(); | |
| 1487 } | |
| 1488 | |
| 1489 void View::ReorderLayers() { | |
| 1490 View* v = this; | |
| 1491 while (v && !v->layer()) | |
| 1492 v = v->parent(); | |
| 1493 | |
| 1494 Widget* widget = GetWidget(); | |
| 1495 if (!v) { | |
| 1496 if (widget) { | |
| 1497 ui::Layer* layer = widget->GetLayer(); | |
| 1498 if (layer) | |
| 1499 widget->GetRootView()->ReorderChildLayers(layer); | |
| 1500 } | |
| 1501 } else { | |
| 1502 v->ReorderChildLayers(v->layer()); | |
| 1503 } | |
| 1504 | |
| 1505 if (widget) { | |
| 1506 // Reorder the widget's child NativeViews in case a child NativeView is | |
| 1507 // associated with a view (eg via a NativeViewHost). Always do the | |
| 1508 // reordering because the associated NativeView's layer (if it has one) | |
| 1509 // is parented to the widget's layer regardless of whether the host view has | |
| 1510 // an ancestor with a layer. | |
| 1511 widget->ReorderNativeViews(); | |
| 1512 } | |
| 1513 } | |
| 1514 | |
| 1515 void View::ReorderChildLayers(ui::Layer* parent_layer) { | |
| 1516 if (layer() && layer() != parent_layer) { | |
| 1517 DCHECK_EQ(parent_layer, layer()->parent()); | |
| 1518 parent_layer->StackAtBottom(layer()); | |
| 1519 } else { | |
| 1520 // Iterate backwards through the children so that a child with a layer | |
| 1521 // which is further to the back is stacked above one which is further to | |
| 1522 // the front. | |
| 1523 for (Views::reverse_iterator it(children_.rbegin()); | |
| 1524 it != children_.rend(); ++it) { | |
| 1525 (*it)->ReorderChildLayers(parent_layer); | |
| 1526 } | |
| 1527 } | |
| 1528 } | |
| 1529 | |
| 1530 // Input ----------------------------------------------------------------------- | |
| 1531 | |
| 1532 View::DragInfo* View::GetDragInfo() { | |
| 1533 return parent_ ? parent_->GetDragInfo() : NULL; | |
| 1534 } | |
| 1535 | |
| 1536 // Focus ----------------------------------------------------------------------- | |
| 1537 | |
| 1538 void View::OnFocus() { | |
| 1539 // TODO(beng): Investigate whether it's possible for us to move this to | |
| 1540 // Focus(). | |
| 1541 // By default, we clear the native focus. This ensures that no visible native | |
| 1542 // view as the focus and that we still receive keyboard inputs. | |
| 1543 FocusManager* focus_manager = GetFocusManager(); | |
| 1544 if (focus_manager) | |
| 1545 focus_manager->ClearNativeFocus(); | |
| 1546 | |
| 1547 // TODO(beng): Investigate whether it's possible for us to move this to | |
| 1548 // Focus(). | |
| 1549 // Notify assistive technologies of the focus change. | |
| 1550 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); | |
| 1551 } | |
| 1552 | |
| 1553 void View::OnBlur() { | |
| 1554 } | |
| 1555 | |
| 1556 void View::Focus() { | |
| 1557 OnFocus(); | |
| 1558 } | |
| 1559 | |
| 1560 void View::Blur() { | |
| 1561 OnBlur(); | |
| 1562 } | |
| 1563 | |
| 1564 // Tooltips -------------------------------------------------------------------- | |
| 1565 | |
| 1566 void View::TooltipTextChanged() { | |
| 1567 Widget* widget = GetWidget(); | |
| 1568 // TooltipManager may be null if there is a problem creating it. | |
| 1569 if (widget && widget->GetTooltipManager()) | |
| 1570 widget->GetTooltipManager()->TooltipTextChanged(this); | |
| 1571 } | |
| 1572 | |
| 1573 // Context menus --------------------------------------------------------------- | |
| 1574 | |
| 1575 gfx::Point View::GetKeyboardContextMenuLocation() { | |
| 1576 gfx::Rect vis_bounds = GetVisibleBounds(); | |
| 1577 gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2, | |
| 1578 vis_bounds.y() + vis_bounds.height() / 2); | |
| 1579 ConvertPointToScreen(this, &screen_point); | |
| 1580 return screen_point; | |
| 1581 } | |
| 1582 | |
| 1583 // Drag and drop --------------------------------------------------------------- | |
| 1584 | |
| 1585 int View::GetDragOperations(const gfx::Point& press_pt) { | |
| 1586 return drag_controller_ ? | |
| 1587 drag_controller_->GetDragOperationsForView(this, press_pt) : | |
| 1588 ui::DragDropTypes::DRAG_NONE; | |
| 1589 } | |
| 1590 | |
| 1591 void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) { | |
| 1592 DCHECK(drag_controller_); | |
| 1593 drag_controller_->WriteDragDataForView(this, press_pt, data); | |
| 1594 } | |
| 1595 | |
| 1596 bool View::InDrag() { | |
| 1597 Widget* widget = GetWidget(); | |
| 1598 return widget ? widget->dragged_view() == this : false; | |
| 1599 } | |
| 1600 | |
| 1601 int View::GetHorizontalDragThreshold() { | |
| 1602 // TODO(jennyz): This value may need to be adjusted for different platforms | |
| 1603 // and for different display density. | |
| 1604 return kDefaultHorizontalDragThreshold; | |
| 1605 } | |
| 1606 | |
| 1607 int View::GetVerticalDragThreshold() { | |
| 1608 // TODO(jennyz): This value may need to be adjusted for different platforms | |
| 1609 // and for different display density. | |
| 1610 return kDefaultVerticalDragThreshold; | |
| 1611 } | |
| 1612 | |
| 1613 // Debugging ------------------------------------------------------------------- | |
| 1614 | |
| 1615 #if !defined(NDEBUG) | |
| 1616 | |
| 1617 std::string View::PrintViewGraph(bool first) { | |
| 1618 return DoPrintViewGraph(first, this); | |
| 1619 } | |
| 1620 | |
| 1621 std::string View::DoPrintViewGraph(bool first, View* view_with_children) { | |
| 1622 // 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19. | |
| 1623 const size_t kMaxPointerStringLength = 19; | |
| 1624 | |
| 1625 std::string result; | |
| 1626 | |
| 1627 if (first) | |
| 1628 result.append("digraph {\n"); | |
| 1629 | |
| 1630 // Node characteristics. | |
| 1631 char p[kMaxPointerStringLength]; | |
| 1632 | |
| 1633 const std::string class_name(GetClassName()); | |
| 1634 size_t base_name_index = class_name.find_last_of('/'); | |
| 1635 if (base_name_index == std::string::npos) | |
| 1636 base_name_index = 0; | |
| 1637 else | |
| 1638 base_name_index++; | |
| 1639 | |
| 1640 char bounds_buffer[512]; | |
| 1641 | |
| 1642 // Information about current node. | |
| 1643 base::snprintf(p, arraysize(bounds_buffer), "%p", view_with_children); | |
| 1644 result.append(" N"); | |
| 1645 result.append(p + 2); | |
| 1646 result.append(" [label=\""); | |
| 1647 | |
| 1648 result.append(class_name.substr(base_name_index).c_str()); | |
| 1649 | |
| 1650 base::snprintf(bounds_buffer, | |
| 1651 arraysize(bounds_buffer), | |
| 1652 "\\n bounds: (%d, %d), (%dx%d)", | |
| 1653 bounds().x(), | |
| 1654 bounds().y(), | |
| 1655 bounds().width(), | |
| 1656 bounds().height()); | |
| 1657 result.append(bounds_buffer); | |
| 1658 | |
| 1659 gfx::DecomposedTransform decomp; | |
| 1660 if (!GetTransform().IsIdentity() && | |
| 1661 gfx::DecomposeTransform(&decomp, GetTransform())) { | |
| 1662 base::snprintf(bounds_buffer, | |
| 1663 arraysize(bounds_buffer), | |
| 1664 "\\n translation: (%f, %f)", | |
| 1665 decomp.translate[0], | |
| 1666 decomp.translate[1]); | |
| 1667 result.append(bounds_buffer); | |
| 1668 | |
| 1669 base::snprintf(bounds_buffer, | |
| 1670 arraysize(bounds_buffer), | |
| 1671 "\\n rotation: %3.2f", | |
| 1672 std::acos(decomp.quaternion[3]) * 360.0 / M_PI); | |
| 1673 result.append(bounds_buffer); | |
| 1674 | |
| 1675 base::snprintf(bounds_buffer, | |
| 1676 arraysize(bounds_buffer), | |
| 1677 "\\n scale: (%2.4f, %2.4f)", | |
| 1678 decomp.scale[0], | |
| 1679 decomp.scale[1]); | |
| 1680 result.append(bounds_buffer); | |
| 1681 } | |
| 1682 | |
| 1683 result.append("\""); | |
| 1684 if (!parent_) | |
| 1685 result.append(", shape=box"); | |
| 1686 if (layer()) { | |
| 1687 if (layer()->has_external_content()) | |
| 1688 result.append(", color=green"); | |
| 1689 else | |
| 1690 result.append(", color=red"); | |
| 1691 | |
| 1692 if (layer()->fills_bounds_opaquely()) | |
| 1693 result.append(", style=filled"); | |
| 1694 } | |
| 1695 result.append("]\n"); | |
| 1696 | |
| 1697 // Link to parent. | |
| 1698 if (parent_) { | |
| 1699 char pp[kMaxPointerStringLength]; | |
| 1700 | |
| 1701 base::snprintf(pp, kMaxPointerStringLength, "%p", parent_); | |
| 1702 result.append(" N"); | |
| 1703 result.append(pp + 2); | |
| 1704 result.append(" -> N"); | |
| 1705 result.append(p + 2); | |
| 1706 result.append("\n"); | |
| 1707 } | |
| 1708 | |
| 1709 // Children. | |
| 1710 for (int i = 0, count = view_with_children->child_count(); i < count; ++i) | |
| 1711 result.append(view_with_children->child_at(i)->PrintViewGraph(false)); | |
| 1712 | |
| 1713 if (first) | |
| 1714 result.append("}\n"); | |
| 1715 | |
| 1716 return result; | |
| 1717 } | |
| 1718 #endif | |
| 1719 | |
| 1720 //////////////////////////////////////////////////////////////////////////////// | |
| 1721 // View, private: | |
| 1722 | |
| 1723 // DropInfo -------------------------------------------------------------------- | |
| 1724 | |
| 1725 void View::DragInfo::Reset() { | |
| 1726 possible_drag = false; | |
| 1727 start_pt = gfx::Point(); | |
| 1728 } | |
| 1729 | |
| 1730 void View::DragInfo::PossibleDrag(const gfx::Point& p) { | |
| 1731 possible_drag = true; | |
| 1732 start_pt = p; | |
| 1733 } | |
| 1734 | |
| 1735 // Painting -------------------------------------------------------------------- | |
| 1736 | |
| 1737 void View::SchedulePaintBoundsChanged(SchedulePaintType type) { | |
| 1738 // If we have a layer and the View's size did not change, we do not need to | |
| 1739 // schedule any paints since the layer will be redrawn at its new location | |
| 1740 // during the next Draw() cycle in the compositor. | |
| 1741 if (!layer() || type == SCHEDULE_PAINT_SIZE_CHANGED) { | |
| 1742 // Otherwise, if the size changes or we don't have a layer then we need to | |
| 1743 // use SchedulePaint to invalidate the area occupied by the View. | |
| 1744 SchedulePaint(); | |
| 1745 } else if (parent_ && type == SCHEDULE_PAINT_SIZE_SAME) { | |
| 1746 // The compositor doesn't Draw() until something on screen changes, so | |
| 1747 // if our position changes but nothing is being animated on screen, then | |
| 1748 // tell the compositor to redraw the scene. We know layer() exists due to | |
| 1749 // the above if clause. | |
| 1750 layer()->ScheduleDraw(); | |
| 1751 } | |
| 1752 } | |
| 1753 | |
| 1754 void View::PaintCommon(gfx::Canvas* canvas, const CullSet& cull_set) { | |
| 1755 if (!visible_) | |
| 1756 return; | |
| 1757 | |
| 1758 { | |
| 1759 // If the View we are about to paint requested the canvas to be flipped, we | |
| 1760 // should change the transform appropriately. | |
| 1761 // The canvas mirroring is undone once the View is done painting so that we | |
| 1762 // don't pass the canvas with the mirrored transform to Views that didn't | |
| 1763 // request the canvas to be flipped. | |
| 1764 gfx::ScopedCanvas scoped(canvas); | |
| 1765 if (FlipCanvasOnPaintForRTLUI()) { | |
| 1766 canvas->Translate(gfx::Vector2d(width(), 0)); | |
| 1767 canvas->Scale(-1, 1); | |
| 1768 } | |
| 1769 | |
| 1770 OnPaint(canvas); | |
| 1771 } | |
| 1772 | |
| 1773 PaintChildren(canvas, cull_set); | |
| 1774 } | |
| 1775 | |
| 1776 // Tree operations ------------------------------------------------------------- | |
| 1777 | |
| 1778 void View::DoRemoveChildView(View* view, | |
| 1779 bool update_focus_cycle, | |
| 1780 bool update_tool_tip, | |
| 1781 bool delete_removed_view, | |
| 1782 View* new_parent) { | |
| 1783 DCHECK(view); | |
| 1784 | |
| 1785 const Views::iterator i(std::find(children_.begin(), children_.end(), view)); | |
| 1786 scoped_ptr<View> view_to_be_deleted; | |
| 1787 if (i != children_.end()) { | |
| 1788 if (update_focus_cycle) { | |
| 1789 // Let's remove the view from the focus traversal. | |
| 1790 View* next_focusable = view->next_focusable_view_; | |
| 1791 View* prev_focusable = view->previous_focusable_view_; | |
| 1792 if (prev_focusable) | |
| 1793 prev_focusable->next_focusable_view_ = next_focusable; | |
| 1794 if (next_focusable) | |
| 1795 next_focusable->previous_focusable_view_ = prev_focusable; | |
| 1796 } | |
| 1797 | |
| 1798 if (GetWidget()) { | |
| 1799 UnregisterChildrenForVisibleBoundsNotification(view); | |
| 1800 if (view->visible()) | |
| 1801 view->SchedulePaint(); | |
| 1802 GetWidget()->NotifyWillRemoveView(view); | |
| 1803 } | |
| 1804 | |
| 1805 // Remove the bounds of this child and any of its descendants from our | |
| 1806 // paint root bounds tree. | |
| 1807 BoundsTree* bounds_tree = GetBoundsTreeFromPaintRoot(); | |
| 1808 if (bounds_tree) | |
| 1809 view->RemoveRootBounds(bounds_tree); | |
| 1810 | |
| 1811 view->PropagateRemoveNotifications(this, new_parent); | |
| 1812 view->parent_ = NULL; | |
| 1813 view->UpdateLayerVisibility(); | |
| 1814 | |
| 1815 if (delete_removed_view && !view->owned_by_client_) | |
| 1816 view_to_be_deleted.reset(view); | |
| 1817 | |
| 1818 children_.erase(i); | |
| 1819 } | |
| 1820 | |
| 1821 if (update_tool_tip) | |
| 1822 UpdateTooltip(); | |
| 1823 | |
| 1824 if (layout_manager_.get()) | |
| 1825 layout_manager_->ViewRemoved(this, view); | |
| 1826 } | |
| 1827 | |
| 1828 void View::PropagateRemoveNotifications(View* old_parent, View* new_parent) { | |
| 1829 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1830 child_at(i)->PropagateRemoveNotifications(old_parent, new_parent); | |
| 1831 | |
| 1832 ViewHierarchyChangedDetails details(false, old_parent, this, new_parent); | |
| 1833 for (View* v = this; v; v = v->parent_) | |
| 1834 v->ViewHierarchyChangedImpl(true, details); | |
| 1835 } | |
| 1836 | |
| 1837 void View::PropagateAddNotifications( | |
| 1838 const ViewHierarchyChangedDetails& details) { | |
| 1839 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1840 child_at(i)->PropagateAddNotifications(details); | |
| 1841 ViewHierarchyChangedImpl(true, details); | |
| 1842 } | |
| 1843 | |
| 1844 void View::PropagateNativeViewHierarchyChanged() { | |
| 1845 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1846 child_at(i)->PropagateNativeViewHierarchyChanged(); | |
| 1847 NativeViewHierarchyChanged(); | |
| 1848 } | |
| 1849 | |
| 1850 void View::ViewHierarchyChangedImpl( | |
| 1851 bool register_accelerators, | |
| 1852 const ViewHierarchyChangedDetails& details) { | |
| 1853 if (register_accelerators) { | |
| 1854 if (details.is_add) { | |
| 1855 // If you get this registration, you are part of a subtree that has been | |
| 1856 // added to the view hierarchy. | |
| 1857 if (GetFocusManager()) | |
| 1858 RegisterPendingAccelerators(); | |
| 1859 } else { | |
| 1860 if (details.child == this) | |
| 1861 UnregisterAccelerators(true); | |
| 1862 } | |
| 1863 } | |
| 1864 | |
| 1865 if (details.is_add && layer() && !layer()->parent()) { | |
| 1866 UpdateParentLayer(); | |
| 1867 Widget* widget = GetWidget(); | |
| 1868 if (widget) | |
| 1869 widget->UpdateRootLayers(); | |
| 1870 } else if (!details.is_add && details.child == this) { | |
| 1871 // Make sure the layers belonging to the subtree rooted at |child| get | |
| 1872 // removed from layers that do not belong in the same subtree. | |
| 1873 OrphanLayers(); | |
| 1874 Widget* widget = GetWidget(); | |
| 1875 if (widget) | |
| 1876 widget->UpdateRootLayers(); | |
| 1877 } | |
| 1878 | |
| 1879 ViewHierarchyChanged(details); | |
| 1880 details.parent->needs_layout_ = true; | |
| 1881 } | |
| 1882 | |
| 1883 void View::PropagateNativeThemeChanged(const ui::NativeTheme* theme) { | |
| 1884 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1885 child_at(i)->PropagateNativeThemeChanged(theme); | |
| 1886 OnNativeThemeChanged(theme); | |
| 1887 } | |
| 1888 | |
| 1889 // Size and disposition -------------------------------------------------------- | |
| 1890 | |
| 1891 void View::PropagateVisibilityNotifications(View* start, bool is_visible) { | |
| 1892 for (int i = 0, count = child_count(); i < count; ++i) | |
| 1893 child_at(i)->PropagateVisibilityNotifications(start, is_visible); | |
| 1894 VisibilityChangedImpl(start, is_visible); | |
| 1895 } | |
| 1896 | |
| 1897 void View::VisibilityChangedImpl(View* starting_from, bool is_visible) { | |
| 1898 VisibilityChanged(starting_from, is_visible); | |
| 1899 } | |
| 1900 | |
| 1901 void View::BoundsChanged(const gfx::Rect& previous_bounds) { | |
| 1902 // Mark our bounds as dirty for the paint root, also see if we need to | |
| 1903 // recompute our children's bounds due to origin change. | |
| 1904 bool origin_changed = | |
| 1905 previous_bounds.OffsetFromOrigin() != bounds_.OffsetFromOrigin(); | |
| 1906 SetRootBoundsDirty(origin_changed); | |
| 1907 | |
| 1908 if (visible_) { | |
| 1909 // Paint the new bounds. | |
| 1910 SchedulePaintBoundsChanged( | |
| 1911 bounds_.size() == previous_bounds.size() ? SCHEDULE_PAINT_SIZE_SAME : | |
| 1912 SCHEDULE_PAINT_SIZE_CHANGED); | |
| 1913 } | |
| 1914 | |
| 1915 if (layer()) { | |
| 1916 if (parent_) { | |
| 1917 SetLayerBounds(GetLocalBounds() + | |
| 1918 gfx::Vector2d(GetMirroredX(), y()) + | |
| 1919 parent_->CalculateOffsetToAncestorWithLayer(NULL)); | |
| 1920 } else { | |
| 1921 SetLayerBounds(bounds_); | |
| 1922 } | |
| 1923 } else { | |
| 1924 // If our bounds have changed, then any descendant layer bounds may have | |
| 1925 // changed. Update them accordingly. | |
| 1926 UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(NULL)); | |
| 1927 } | |
| 1928 | |
| 1929 OnBoundsChanged(previous_bounds); | |
| 1930 | |
| 1931 if (previous_bounds.size() != size()) { | |
| 1932 needs_layout_ = false; | |
| 1933 Layout(); | |
| 1934 } | |
| 1935 | |
| 1936 if (GetNeedsNotificationWhenVisibleBoundsChange()) | |
| 1937 OnVisibleBoundsChanged(); | |
| 1938 | |
| 1939 // Notify interested Views that visible bounds within the root view may have | |
| 1940 // changed. | |
| 1941 if (descendants_to_notify_.get()) { | |
| 1942 for (Views::iterator i(descendants_to_notify_->begin()); | |
| 1943 i != descendants_to_notify_->end(); ++i) { | |
| 1944 (*i)->OnVisibleBoundsChanged(); | |
| 1945 } | |
| 1946 } | |
| 1947 } | |
| 1948 | |
| 1949 // static | |
| 1950 void View::RegisterChildrenForVisibleBoundsNotification(View* view) { | |
| 1951 if (view->GetNeedsNotificationWhenVisibleBoundsChange()) | |
| 1952 view->RegisterForVisibleBoundsNotification(); | |
| 1953 for (int i = 0; i < view->child_count(); ++i) | |
| 1954 RegisterChildrenForVisibleBoundsNotification(view->child_at(i)); | |
| 1955 } | |
| 1956 | |
| 1957 // static | |
| 1958 void View::UnregisterChildrenForVisibleBoundsNotification(View* view) { | |
| 1959 if (view->GetNeedsNotificationWhenVisibleBoundsChange()) | |
| 1960 view->UnregisterForVisibleBoundsNotification(); | |
| 1961 for (int i = 0; i < view->child_count(); ++i) | |
| 1962 UnregisterChildrenForVisibleBoundsNotification(view->child_at(i)); | |
| 1963 } | |
| 1964 | |
| 1965 void View::RegisterForVisibleBoundsNotification() { | |
| 1966 if (registered_for_visible_bounds_notification_) | |
| 1967 return; | |
| 1968 | |
| 1969 registered_for_visible_bounds_notification_ = true; | |
| 1970 for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_) | |
| 1971 ancestor->AddDescendantToNotify(this); | |
| 1972 } | |
| 1973 | |
| 1974 void View::UnregisterForVisibleBoundsNotification() { | |
| 1975 if (!registered_for_visible_bounds_notification_) | |
| 1976 return; | |
| 1977 | |
| 1978 registered_for_visible_bounds_notification_ = false; | |
| 1979 for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_) | |
| 1980 ancestor->RemoveDescendantToNotify(this); | |
| 1981 } | |
| 1982 | |
| 1983 void View::AddDescendantToNotify(View* view) { | |
| 1984 DCHECK(view); | |
| 1985 if (!descendants_to_notify_.get()) | |
| 1986 descendants_to_notify_.reset(new Views); | |
| 1987 descendants_to_notify_->push_back(view); | |
| 1988 } | |
| 1989 | |
| 1990 void View::RemoveDescendantToNotify(View* view) { | |
| 1991 DCHECK(view && descendants_to_notify_.get()); | |
| 1992 Views::iterator i(std::find( | |
| 1993 descendants_to_notify_->begin(), descendants_to_notify_->end(), view)); | |
| 1994 DCHECK(i != descendants_to_notify_->end()); | |
| 1995 descendants_to_notify_->erase(i); | |
| 1996 if (descendants_to_notify_->empty()) | |
| 1997 descendants_to_notify_.reset(); | |
| 1998 } | |
| 1999 | |
| 2000 void View::SetLayerBounds(const gfx::Rect& bounds) { | |
| 2001 layer()->SetBounds(bounds); | |
| 2002 SnapLayerToPixelBoundary(); | |
| 2003 } | |
| 2004 | |
| 2005 void View::SetRootBoundsDirty(bool origin_changed) { | |
| 2006 root_bounds_dirty_ = true; | |
| 2007 | |
| 2008 if (origin_changed) { | |
| 2009 // Inform our children that their root bounds are dirty, as their relative | |
| 2010 // coordinates in paint root space have changed since ours have changed. | |
| 2011 for (Views::const_iterator i(children_.begin()); i != children_.end(); | |
| 2012 ++i) { | |
| 2013 if (!(*i)->IsPaintRoot()) | |
| 2014 (*i)->SetRootBoundsDirty(origin_changed); | |
| 2015 } | |
| 2016 } | |
| 2017 } | |
| 2018 | |
| 2019 void View::UpdateRootBounds(BoundsTree* tree, const gfx::Vector2d& offset) { | |
| 2020 // If we're not visible no need to update BoundsTree. When we are made visible | |
| 2021 // the BoundsTree will be updated appropriately. | |
| 2022 if (!visible_) | |
| 2023 return; | |
| 2024 | |
| 2025 if (!root_bounds_dirty_ && children_.empty()) | |
| 2026 return; | |
| 2027 | |
| 2028 // No need to recompute bounds if we haven't flagged ours as dirty. | |
| 2029 TRACE_EVENT1("views", "View::UpdateRootBounds", "class", GetClassName()); | |
| 2030 | |
| 2031 // Add our own offset to the provided offset, for our own bounds update and | |
| 2032 // for propagation to our children if needed. | |
| 2033 gfx::Vector2d view_offset = offset + GetMirroredBounds().OffsetFromOrigin(); | |
| 2034 | |
| 2035 // If our bounds have changed we must re-insert our new bounds to the tree. | |
| 2036 if (root_bounds_dirty_) { | |
| 2037 root_bounds_dirty_ = false; | |
| 2038 gfx::Rect bounds( | |
| 2039 view_offset.x(), view_offset.y(), bounds_.width(), bounds_.height()); | |
| 2040 tree->Insert(bounds, reinterpret_cast<intptr_t>(this)); | |
| 2041 } | |
| 2042 | |
| 2043 // Update our children's bounds if needed. | |
| 2044 for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) { | |
| 2045 // We don't descend in to layer views for bounds recomputation, as they | |
| 2046 // manage their own RTree as paint roots. | |
| 2047 if (!(*i)->IsPaintRoot()) | |
| 2048 (*i)->UpdateRootBounds(tree, view_offset); | |
| 2049 } | |
| 2050 } | |
| 2051 | |
| 2052 void View::RemoveRootBounds(BoundsTree* tree) { | |
| 2053 tree->Remove(reinterpret_cast<intptr_t>(this)); | |
| 2054 | |
| 2055 root_bounds_dirty_ = true; | |
| 2056 | |
| 2057 for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) { | |
| 2058 if (!(*i)->IsPaintRoot()) | |
| 2059 (*i)->RemoveRootBounds(tree); | |
| 2060 } | |
| 2061 } | |
| 2062 | |
| 2063 View::BoundsTree* View::GetBoundsTreeFromPaintRoot() { | |
| 2064 BoundsTree* bounds_tree = bounds_tree_.get(); | |
| 2065 View* paint_root = this; | |
| 2066 while (!bounds_tree && !paint_root->IsPaintRoot()) { | |
| 2067 // Assumption is that if IsPaintRoot() is false then parent_ is valid. | |
| 2068 DCHECK(paint_root); | |
| 2069 paint_root = paint_root->parent_; | |
| 2070 bounds_tree = paint_root->bounds_tree_.get(); | |
| 2071 } | |
| 2072 | |
| 2073 return bounds_tree; | |
| 2074 } | |
| 2075 | |
| 2076 // Transformations ------------------------------------------------------------- | |
| 2077 | |
| 2078 bool View::GetTransformRelativeTo(const View* ancestor, | |
| 2079 gfx::Transform* transform) const { | |
| 2080 const View* p = this; | |
| 2081 | |
| 2082 while (p && p != ancestor) { | |
| 2083 transform->ConcatTransform(p->GetTransform()); | |
| 2084 gfx::Transform translation; | |
| 2085 translation.Translate(static_cast<float>(p->GetMirroredX()), | |
| 2086 static_cast<float>(p->y())); | |
| 2087 transform->ConcatTransform(translation); | |
| 2088 | |
| 2089 p = p->parent_; | |
| 2090 } | |
| 2091 | |
| 2092 return p == ancestor; | |
| 2093 } | |
| 2094 | |
| 2095 // Coordinate conversion ------------------------------------------------------- | |
| 2096 | |
| 2097 bool View::ConvertPointForAncestor(const View* ancestor, | |
| 2098 gfx::Point* point) const { | |
| 2099 gfx::Transform trans; | |
| 2100 // TODO(sad): Have some way of caching the transformation results. | |
| 2101 bool result = GetTransformRelativeTo(ancestor, &trans); | |
| 2102 gfx::Point3F p(*point); | |
| 2103 trans.TransformPoint(&p); | |
| 2104 *point = gfx::ToFlooredPoint(p.AsPointF()); | |
| 2105 return result; | |
| 2106 } | |
| 2107 | |
| 2108 bool View::ConvertPointFromAncestor(const View* ancestor, | |
| 2109 gfx::Point* point) const { | |
| 2110 gfx::Transform trans; | |
| 2111 bool result = GetTransformRelativeTo(ancestor, &trans); | |
| 2112 gfx::Point3F p(*point); | |
| 2113 trans.TransformPointReverse(&p); | |
| 2114 *point = gfx::ToFlooredPoint(p.AsPointF()); | |
| 2115 return result; | |
| 2116 } | |
| 2117 | |
| 2118 bool View::ConvertRectForAncestor(const View* ancestor, | |
| 2119 gfx::RectF* rect) const { | |
| 2120 gfx::Transform trans; | |
| 2121 // TODO(sad): Have some way of caching the transformation results. | |
| 2122 bool result = GetTransformRelativeTo(ancestor, &trans); | |
| 2123 trans.TransformRect(rect); | |
| 2124 return result; | |
| 2125 } | |
| 2126 | |
| 2127 bool View::ConvertRectFromAncestor(const View* ancestor, | |
| 2128 gfx::RectF* rect) const { | |
| 2129 gfx::Transform trans; | |
| 2130 bool result = GetTransformRelativeTo(ancestor, &trans); | |
| 2131 trans.TransformRectReverse(rect); | |
| 2132 return result; | |
| 2133 } | |
| 2134 | |
| 2135 // Accelerated painting -------------------------------------------------------- | |
| 2136 | |
| 2137 void View::CreateLayer() { | |
| 2138 // A new layer is being created for the view. So all the layers of the | |
| 2139 // sub-tree can inherit the visibility of the corresponding view. | |
| 2140 for (int i = 0, count = child_count(); i < count; ++i) | |
| 2141 child_at(i)->UpdateChildLayerVisibility(true); | |
| 2142 | |
| 2143 SetLayer(new ui::Layer()); | |
| 2144 layer()->set_delegate(this); | |
| 2145 #if !defined(NDEBUG) | |
| 2146 layer()->set_name(GetClassName()); | |
| 2147 #endif | |
| 2148 | |
| 2149 UpdateParentLayers(); | |
| 2150 UpdateLayerVisibility(); | |
| 2151 | |
| 2152 // The new layer needs to be ordered in the layer tree according | |
| 2153 // to the view tree. Children of this layer were added in order | |
| 2154 // in UpdateParentLayers(). | |
| 2155 if (parent()) | |
| 2156 parent()->ReorderLayers(); | |
| 2157 | |
| 2158 Widget* widget = GetWidget(); | |
| 2159 if (widget) | |
| 2160 widget->UpdateRootLayers(); | |
| 2161 } | |
| 2162 | |
| 2163 void View::UpdateParentLayers() { | |
| 2164 // Attach all top-level un-parented layers. | |
| 2165 if (layer() && !layer()->parent()) { | |
| 2166 UpdateParentLayer(); | |
| 2167 } else { | |
| 2168 for (int i = 0, count = child_count(); i < count; ++i) | |
| 2169 child_at(i)->UpdateParentLayers(); | |
| 2170 } | |
| 2171 } | |
| 2172 | |
| 2173 void View::OrphanLayers() { | |
| 2174 if (layer()) { | |
| 2175 if (layer()->parent()) | |
| 2176 layer()->parent()->Remove(layer()); | |
| 2177 | |
| 2178 // The layer belonging to this View has already been orphaned. It is not | |
| 2179 // necessary to orphan the child layers. | |
| 2180 return; | |
| 2181 } | |
| 2182 for (int i = 0, count = child_count(); i < count; ++i) | |
| 2183 child_at(i)->OrphanLayers(); | |
| 2184 } | |
| 2185 | |
| 2186 void View::ReparentLayer(const gfx::Vector2d& offset, ui::Layer* parent_layer) { | |
| 2187 layer()->SetBounds(GetLocalBounds() + offset); | |
| 2188 DCHECK_NE(layer(), parent_layer); | |
| 2189 if (parent_layer) | |
| 2190 parent_layer->Add(layer()); | |
| 2191 layer()->SchedulePaint(GetLocalBounds()); | |
| 2192 MoveLayerToParent(layer(), gfx::Point()); | |
| 2193 } | |
| 2194 | |
| 2195 void View::DestroyLayer() { | |
| 2196 ui::Layer* new_parent = layer()->parent(); | |
| 2197 std::vector<ui::Layer*> children = layer()->children(); | |
| 2198 for (size_t i = 0; i < children.size(); ++i) { | |
| 2199 layer()->Remove(children[i]); | |
| 2200 if (new_parent) | |
| 2201 new_parent->Add(children[i]); | |
| 2202 } | |
| 2203 | |
| 2204 LayerOwner::DestroyLayer(); | |
| 2205 | |
| 2206 if (new_parent) | |
| 2207 ReorderLayers(); | |
| 2208 | |
| 2209 UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(NULL)); | |
| 2210 | |
| 2211 SchedulePaint(); | |
| 2212 | |
| 2213 Widget* widget = GetWidget(); | |
| 2214 if (widget) | |
| 2215 widget->UpdateRootLayers(); | |
| 2216 } | |
| 2217 | |
| 2218 // Input ----------------------------------------------------------------------- | |
| 2219 | |
| 2220 bool View::ProcessMousePressed(const ui::MouseEvent& event) { | |
| 2221 int drag_operations = | |
| 2222 (enabled_ && event.IsOnlyLeftMouseButton() && | |
| 2223 HitTestPoint(event.location())) ? | |
| 2224 GetDragOperations(event.location()) : 0; | |
| 2225 ContextMenuController* context_menu_controller = event.IsRightMouseButton() ? | |
| 2226 context_menu_controller_ : 0; | |
| 2227 View::DragInfo* drag_info = GetDragInfo(); | |
| 2228 | |
| 2229 // TODO(sky): for debugging 360238. | |
| 2230 int storage_id = 0; | |
| 2231 if (event.IsOnlyRightMouseButton() && context_menu_controller && | |
| 2232 kContextMenuOnMousePress && HitTestPoint(event.location())) { | |
| 2233 ViewStorage* view_storage = ViewStorage::GetInstance(); | |
| 2234 storage_id = view_storage->CreateStorageID(); | |
| 2235 view_storage->StoreView(storage_id, this); | |
| 2236 } | |
| 2237 | |
| 2238 const bool enabled = enabled_; | |
| 2239 const bool result = OnMousePressed(event); | |
| 2240 | |
| 2241 if (!enabled) | |
| 2242 return result; | |
| 2243 | |
| 2244 if (event.IsOnlyRightMouseButton() && context_menu_controller && | |
| 2245 kContextMenuOnMousePress) { | |
| 2246 // Assume that if there is a context menu controller we won't be deleted | |
| 2247 // from mouse pressed. | |
| 2248 gfx::Point location(event.location()); | |
| 2249 if (HitTestPoint(location)) { | |
| 2250 if (storage_id != 0) | |
| 2251 CHECK_EQ(this, ViewStorage::GetInstance()->RetrieveView(storage_id)); | |
| 2252 ConvertPointToScreen(this, &location); | |
| 2253 ShowContextMenu(location, ui::MENU_SOURCE_MOUSE); | |
| 2254 return true; | |
| 2255 } | |
| 2256 } | |
| 2257 | |
| 2258 // WARNING: we may have been deleted, don't use any View variables. | |
| 2259 if (drag_operations != ui::DragDropTypes::DRAG_NONE) { | |
| 2260 drag_info->PossibleDrag(event.location()); | |
| 2261 return true; | |
| 2262 } | |
| 2263 return !!context_menu_controller || result; | |
| 2264 } | |
| 2265 | |
| 2266 bool View::ProcessMouseDragged(const ui::MouseEvent& event) { | |
| 2267 // Copy the field, that way if we're deleted after drag and drop no harm is | |
| 2268 // done. | |
| 2269 ContextMenuController* context_menu_controller = context_menu_controller_; | |
| 2270 const bool possible_drag = GetDragInfo()->possible_drag; | |
| 2271 if (possible_drag && | |
| 2272 ExceededDragThreshold(GetDragInfo()->start_pt - event.location()) && | |
| 2273 (!drag_controller_ || | |
| 2274 drag_controller_->CanStartDragForView( | |
| 2275 this, GetDragInfo()->start_pt, event.location()))) { | |
| 2276 DoDrag(event, GetDragInfo()->start_pt, | |
| 2277 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); | |
| 2278 } else { | |
| 2279 if (OnMouseDragged(event)) | |
| 2280 return true; | |
| 2281 // Fall through to return value based on context menu controller. | |
| 2282 } | |
| 2283 // WARNING: we may have been deleted. | |
| 2284 return (context_menu_controller != NULL) || possible_drag; | |
| 2285 } | |
| 2286 | |
| 2287 void View::ProcessMouseReleased(const ui::MouseEvent& event) { | |
| 2288 if (!kContextMenuOnMousePress && context_menu_controller_ && | |
| 2289 event.IsOnlyRightMouseButton()) { | |
| 2290 // Assume that if there is a context menu controller we won't be deleted | |
| 2291 // from mouse released. | |
| 2292 gfx::Point location(event.location()); | |
| 2293 OnMouseReleased(event); | |
| 2294 if (HitTestPoint(location)) { | |
| 2295 ConvertPointToScreen(this, &location); | |
| 2296 ShowContextMenu(location, ui::MENU_SOURCE_MOUSE); | |
| 2297 } | |
| 2298 } else { | |
| 2299 OnMouseReleased(event); | |
| 2300 } | |
| 2301 // WARNING: we may have been deleted. | |
| 2302 } | |
| 2303 | |
| 2304 // Accelerators ---------------------------------------------------------------- | |
| 2305 | |
| 2306 void View::RegisterPendingAccelerators() { | |
| 2307 if (!accelerators_.get() || | |
| 2308 registered_accelerator_count_ == accelerators_->size()) { | |
| 2309 // No accelerators are waiting for registration. | |
| 2310 return; | |
| 2311 } | |
| 2312 | |
| 2313 if (!GetWidget()) { | |
| 2314 // The view is not yet attached to a widget, defer registration until then. | |
| 2315 return; | |
| 2316 } | |
| 2317 | |
| 2318 accelerator_focus_manager_ = GetFocusManager(); | |
| 2319 if (!accelerator_focus_manager_) { | |
| 2320 // Some crash reports seem to show that we may get cases where we have no | |
| 2321 // focus manager (see bug #1291225). This should never be the case, just | |
| 2322 // making sure we don't crash. | |
| 2323 NOTREACHED(); | |
| 2324 return; | |
| 2325 } | |
| 2326 for (std::vector<ui::Accelerator>::const_iterator i( | |
| 2327 accelerators_->begin() + registered_accelerator_count_); | |
| 2328 i != accelerators_->end(); ++i) { | |
| 2329 accelerator_focus_manager_->RegisterAccelerator( | |
| 2330 *i, ui::AcceleratorManager::kNormalPriority, this); | |
| 2331 } | |
| 2332 registered_accelerator_count_ = accelerators_->size(); | |
| 2333 } | |
| 2334 | |
| 2335 void View::UnregisterAccelerators(bool leave_data_intact) { | |
| 2336 if (!accelerators_.get()) | |
| 2337 return; | |
| 2338 | |
| 2339 if (GetWidget()) { | |
| 2340 if (accelerator_focus_manager_) { | |
| 2341 accelerator_focus_manager_->UnregisterAccelerators(this); | |
| 2342 accelerator_focus_manager_ = NULL; | |
| 2343 } | |
| 2344 if (!leave_data_intact) { | |
| 2345 accelerators_->clear(); | |
| 2346 accelerators_.reset(); | |
| 2347 } | |
| 2348 registered_accelerator_count_ = 0; | |
| 2349 } | |
| 2350 } | |
| 2351 | |
| 2352 // Focus ----------------------------------------------------------------------- | |
| 2353 | |
| 2354 void View::InitFocusSiblings(View* v, int index) { | |
| 2355 int count = child_count(); | |
| 2356 | |
| 2357 if (count == 0) { | |
| 2358 v->next_focusable_view_ = NULL; | |
| 2359 v->previous_focusable_view_ = NULL; | |
| 2360 } else { | |
| 2361 if (index == count) { | |
| 2362 // We are inserting at the end, but the end of the child list may not be | |
| 2363 // the last focusable element. Let's try to find an element with no next | |
| 2364 // focusable element to link to. | |
| 2365 View* last_focusable_view = NULL; | |
| 2366 for (Views::iterator i(children_.begin()); i != children_.end(); ++i) { | |
| 2367 if (!(*i)->next_focusable_view_) { | |
| 2368 last_focusable_view = *i; | |
| 2369 break; | |
| 2370 } | |
| 2371 } | |
| 2372 if (last_focusable_view == NULL) { | |
| 2373 // Hum... there is a cycle in the focus list. Let's just insert ourself | |
| 2374 // after the last child. | |
| 2375 View* prev = children_[index - 1]; | |
| 2376 v->previous_focusable_view_ = prev; | |
| 2377 v->next_focusable_view_ = prev->next_focusable_view_; | |
| 2378 prev->next_focusable_view_->previous_focusable_view_ = v; | |
| 2379 prev->next_focusable_view_ = v; | |
| 2380 } else { | |
| 2381 last_focusable_view->next_focusable_view_ = v; | |
| 2382 v->next_focusable_view_ = NULL; | |
| 2383 v->previous_focusable_view_ = last_focusable_view; | |
| 2384 } | |
| 2385 } else { | |
| 2386 View* prev = children_[index]->GetPreviousFocusableView(); | |
| 2387 v->previous_focusable_view_ = prev; | |
| 2388 v->next_focusable_view_ = children_[index]; | |
| 2389 if (prev) | |
| 2390 prev->next_focusable_view_ = v; | |
| 2391 children_[index]->previous_focusable_view_ = v; | |
| 2392 } | |
| 2393 } | |
| 2394 } | |
| 2395 | |
| 2396 void View::AdvanceFocusIfNecessary() { | |
| 2397 // Focus should only be advanced if this is the focused view and has become | |
| 2398 // unfocusable. If the view is still focusable or is not focused, we can | |
| 2399 // return early avoiding furthur unnecessary checks. Focusability check is | |
| 2400 // performed first as it tends to be faster. | |
| 2401 if (IsAccessibilityFocusable() || !HasFocus()) | |
| 2402 return; | |
| 2403 | |
| 2404 FocusManager* focus_manager = GetFocusManager(); | |
| 2405 if (focus_manager) | |
| 2406 focus_manager->AdvanceFocusIfNecessary(); | |
| 2407 } | |
| 2408 | |
| 2409 // System events --------------------------------------------------------------- | |
| 2410 | |
| 2411 void View::PropagateThemeChanged() { | |
| 2412 for (int i = child_count() - 1; i >= 0; --i) | |
| 2413 child_at(i)->PropagateThemeChanged(); | |
| 2414 OnThemeChanged(); | |
| 2415 } | |
| 2416 | |
| 2417 void View::PropagateLocaleChanged() { | |
| 2418 for (int i = child_count() - 1; i >= 0; --i) | |
| 2419 child_at(i)->PropagateLocaleChanged(); | |
| 2420 OnLocaleChanged(); | |
| 2421 } | |
| 2422 | |
| 2423 // Tooltips -------------------------------------------------------------------- | |
| 2424 | |
| 2425 void View::UpdateTooltip() { | |
| 2426 Widget* widget = GetWidget(); | |
| 2427 // TODO(beng): The TooltipManager NULL check can be removed when we | |
| 2428 // consolidate Init() methods and make views_unittests Init() all | |
| 2429 // Widgets that it uses. | |
| 2430 if (widget && widget->GetTooltipManager()) | |
| 2431 widget->GetTooltipManager()->UpdateTooltip(); | |
| 2432 } | |
| 2433 | |
| 2434 // Drag and drop --------------------------------------------------------------- | |
| 2435 | |
| 2436 bool View::DoDrag(const ui::LocatedEvent& event, | |
| 2437 const gfx::Point& press_pt, | |
| 2438 ui::DragDropTypes::DragEventSource source) { | |
| 2439 int drag_operations = GetDragOperations(press_pt); | |
| 2440 if (drag_operations == ui::DragDropTypes::DRAG_NONE) | |
| 2441 return false; | |
| 2442 | |
| 2443 Widget* widget = GetWidget(); | |
| 2444 // We should only start a drag from an event, implying we have a widget. | |
| 2445 DCHECK(widget); | |
| 2446 | |
| 2447 // Don't attempt to start a drag while in the process of dragging. This is | |
| 2448 // especially important on X where we can get multiple mouse move events when | |
| 2449 // we start the drag. | |
| 2450 if (widget->dragged_view()) | |
| 2451 return false; | |
| 2452 | |
| 2453 OSExchangeData data; | |
| 2454 WriteDragData(press_pt, &data); | |
| 2455 | |
| 2456 // Message the RootView to do the drag and drop. That way if we're removed | |
| 2457 // the RootView can detect it and avoid calling us back. | |
| 2458 gfx::Point widget_location(event.location()); | |
| 2459 ConvertPointToWidget(this, &widget_location); | |
| 2460 widget->RunShellDrag(this, data, widget_location, drag_operations, source); | |
| 2461 // WARNING: we may have been deleted. | |
| 2462 return true; | |
| 2463 } | |
| 2464 | |
| 2465 } // namespace views | |
| OLD | NEW |