Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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 #include "ui/views/view.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <functional> | |
| 9 | |
| 10 #include "gfx/canvas.h" | |
| 11 #include "gfx/point.h" | |
| 12 #include "gfx/size.h" | |
| 13 #include "ui/base/dragdrop/drag_drop_types.h" | |
| 14 #include "ui/views/events/context_menu_controller.h" | |
| 15 #include "ui/views/events/drag_controller.h" | |
| 16 #include "ui/views/layout/layout_manager.h" | |
| 17 #include "ui/views/rendering/border.h" | |
| 18 #include "ui/views/widget/widget.h" | |
| 19 | |
| 20 namespace ui { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 // Saves gfx::Canvas state upon construction and automatically restores it when | |
| 25 // it goes out of scope. | |
| 26 class ScopedCanvasState { | |
| 27 public: | |
| 28 explicit ScopedCanvasState(gfx::Canvas* canvas) : canvas_(canvas) { | |
| 29 canvas_->Save(); | |
| 30 } | |
| 31 ~ScopedCanvasState() { | |
| 32 canvas_->Restore(); | |
| 33 } | |
| 34 | |
| 35 private: | |
| 36 gfx::Canvas* canvas_; | |
| 37 DISALLOW_COPY_AND_ASSIGN(ScopedCanvasState); | |
| 38 }; | |
| 39 | |
| 40 bool ExceededDragThreshold(const gfx::Point& press_point, | |
| 41 const gfx::Point& event_point) { | |
| 42 return true; | |
|
sky
2011/02/01 18:56:22
TODO?
| |
| 43 } | |
| 44 | |
| 45 } // namespace | |
| 46 | |
| 47 //////////////////////////////////////////////////////////////////////////////// | |
| 48 // View, public: | |
| 49 | |
| 50 View::View() | |
| 51 : parent_(NULL), | |
| 52 parent_owned_(true), | |
| 53 visible_(true), | |
| 54 enabled_(true), | |
| 55 id_(-1), | |
| 56 group_(-1), | |
| 57 focusable_(false), | |
| 58 context_menu_controller_(NULL), | |
| 59 drag_controller_(NULL) { | |
| 60 } | |
| 61 | |
| 62 View::~View() { | |
| 63 if (parent_) | |
| 64 parent_->RemoveChildView(this); | |
| 65 | |
| 66 ViewVector::const_iterator it = children_.begin(); | |
| 67 for (; it != children_.end(); ++it) { | |
| 68 (*it)->parent_ = NULL; | |
| 69 if ((*it)->parent_owned()) | |
| 70 delete *it; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 // Size and disposition -------------------------------------------------------- | |
| 75 | |
| 76 void View::SetBounds(int x, int y, int width, int height) { | |
| 77 SetBoundsRect(gfx::Rect(x, y, std::max(0, width), std::max(0, height))); | |
| 78 } | |
| 79 | |
| 80 void View::SetBoundsRect(const gfx::Rect& bounds) { | |
| 81 gfx::Rect old_bounds = bounds_; | |
| 82 bounds_ = bounds; | |
| 83 if (old_bounds != bounds_) | |
| 84 OnBoundsChanged(); | |
| 85 } | |
|
sky
2011/02/01 18:56:22
You sure you don't want the:
if (bounds == bounds
| |
| 86 | |
| 87 gfx::Rect View::GetVisibleBounds() const { | |
| 88 // TODO(beng): | |
| 89 return bounds(); | |
| 90 } | |
| 91 | |
| 92 void View::SetSize(const gfx::Size& size) { | |
| 93 SetBounds(x(), y(), size.width(), size.height()); | |
| 94 } | |
| 95 | |
| 96 void View::SetPosition(const gfx::Point& position) { | |
| 97 SetBounds(position.x(), position.y(), width(), height()); | |
| 98 } | |
| 99 | |
| 100 void View::SetBorder(Border* border) { | |
| 101 border_.reset(border); | |
| 102 } | |
| 103 | |
| 104 gfx::Rect View::GetContentsBounds() const { | |
| 105 if (border_.get()) { | |
| 106 return gfx::Rect( | |
| 107 border_->insets().left(), border_->insets().top(), | |
| 108 width() - border_->insets().right() - border_->insets().left(), | |
| 109 height() - border_->insets().bottom() - border_->insets().top()); | |
| 110 } | |
| 111 return gfx::Rect(0, 0, width(), height()); | |
| 112 } | |
| 113 | |
| 114 gfx::Size View::GetPreferredSize() const { | |
| 115 return gfx::Size(); | |
| 116 } | |
| 117 | |
| 118 gfx::Size View::GetMinimumSize() const { | |
| 119 return GetPreferredSize(); | |
| 120 } | |
| 121 | |
| 122 void View::SetLayoutManager(LayoutManager* layout_manager) { | |
| 123 layout_manager_.reset(layout_manager); | |
| 124 } | |
| 125 | |
| 126 void View::Layout() { | |
| 127 if (layout_manager_.get()) { | |
| 128 // Layout Manager handles laying out children. | |
| 129 layout_manager_->Layout(this); | |
| 130 } else { | |
| 131 // We handle laying out our own children. | |
| 132 ViewVector::iterator it = children_.begin(); | |
| 133 for (; it != children_.end(); ++it) | |
| 134 (*it)->Layout(); | |
| 135 } | |
| 136 } | |
|
sky
2011/02/01 18:56:22
This is missing some trickier bits. Specifically S
| |
| 137 | |
| 138 void View::SetVisible(bool visible) { | |
| 139 if (visible != visible_) { | |
| 140 visible_ = visible; | |
| 141 Invalidate(); | |
|
sky
2011/02/01 18:56:22
Because Invalidate does nothing if !visible_, you
| |
| 142 } | |
| 143 } | |
| 144 | |
| 145 void View::SetEnabled(bool enabled) { | |
| 146 if (enabled != enabled_) { | |
| 147 enabled_ = enabled; | |
| 148 Invalidate(); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 void View::OnBoundsChanged() { | |
| 153 Layout(); | |
| 154 } | |
| 155 | |
| 156 // Coordinate conversion ------------------------------------------------------- | |
| 157 | |
| 158 // static | |
| 159 void View::ConvertPointToView(View* source, View* target, gfx::Point* point) { | |
| 160 View* inner = NULL; | |
| 161 View* outer = NULL; | |
| 162 if (source->Contains(target)) { | |
| 163 inner = target; | |
| 164 outer = source; | |
| 165 } else if (target->Contains(source)) { | |
| 166 inner = source; | |
| 167 outer = target; | |
| 168 } // Note that we cannot do a plain "else" here since |source| and |target| | |
| 169 // may be in different hierarchies with no relation. | |
| 170 | |
| 171 if (inner && outer) { | |
| 172 gfx::Point offset; | |
| 173 View* temp = inner; | |
| 174 while (temp != outer) { | |
| 175 offset.Offset(temp->x(), temp->y()); | |
| 176 temp = temp->parent(); | |
| 177 } | |
| 178 // When target is contained by source, we need to subtract the offset. | |
| 179 // When source is contained by target, we need to add the fofset. | |
| 180 int multiplier = inner == target ? -1 : 1; | |
| 181 point->Offset(multiplier * offset.x(), multiplier * offset.y()); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 // static | |
| 186 void View::ConvertPointToScreen(View* source, gfx::Point* point) { | |
| 187 Widget* widget = source->GetWidget(); | |
| 188 if (widget) { | |
| 189 ConvertPointToWidget(source, point); | |
| 190 gfx::Rect r = widget->GetClientAreaScreenBounds(); | |
| 191 point->Offset(r.x(), r.y()); | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 // static | |
| 196 void View::ConvertPointToWidget(View* source, gfx::Point* point) { | |
| 197 for (View* v = source; v; v = v->parent()) | |
| 198 point->Offset(v->x(), v->y()); | |
| 199 } | |
| 200 | |
| 201 // Tree operations ------------------------------------------------------------- | |
| 202 | |
| 203 Widget* View::GetWidget() const { | |
| 204 return parent_ ? parent_->GetWidget() : NULL; | |
| 205 } | |
| 206 | |
| 207 void View::AddChildView(View* view) { | |
| 208 AddChildViewAt(view, children_.size()); | |
| 209 } | |
| 210 | |
| 211 void View::AddChildViewAt(View* view, size_t index) { | |
| 212 CHECK(view != this) << "A view cannot be its own child."; | |
| 213 | |
| 214 // Remove the child from its current parent if any. | |
| 215 if (view->parent()) | |
| 216 view->parent()->RemoveChildView(view); | |
| 217 | |
| 218 children_.insert(children_.begin() + index, view); | |
| 219 view->parent_ = this; | |
| 220 | |
| 221 // Notify the hierarchy. | |
| 222 NotifyHierarchyChanged(this, view, true); | |
| 223 | |
| 224 // TODO(beng): Notify other objects like tooltip, layout manager, etc. | |
|
sky
2011/02/01 18:56:22
and child bounds notification and focus initializa
Ben Goodger (Google)
2011/02/01 20:04:57
I actually want to try and see if I can remove the
| |
| 225 } | |
| 226 | |
| 227 View* View::RemoveChildView(View* view) { | |
| 228 ViewVector::iterator it = find(children_.begin(), children_.end(), view); | |
| 229 if (it != children_.end()) { | |
| 230 View* old_parent = view->parent_; | |
| 231 view->parent_ = NULL; | |
| 232 children_.erase(it); | |
| 233 NotifyHierarchyChanged(old_parent, view, false); | |
| 234 } | |
| 235 | |
| 236 // TODO(beng): Notify other objects like tooltip, layout manager, etc. | |
| 237 return view; | |
| 238 } | |
| 239 | |
| 240 void View::RemoveAllChildViews(bool delete_children) { | |
| 241 // TODO(beng): use for_each. | |
| 242 ViewVector::iterator it = children_.begin(); | |
| 243 while (it != children_.end()) | |
| 244 RemoveChildView(*it); | |
|
sky
2011/02/01 18:56:22
This needs to honor delete_children.
| |
| 245 } | |
| 246 | |
| 247 View* View::GetChildViewAt(size_t index) { | |
| 248 CHECK(index < child_count()); | |
| 249 return children_[index]; | |
| 250 } | |
| 251 | |
| 252 bool View::Contains(View* child) { | |
| 253 while (child) { | |
| 254 if (child == this) | |
| 255 return true; | |
| 256 child = child->parent(); | |
| 257 } | |
| 258 return false; | |
| 259 } | |
| 260 | |
| 261 View* View::GetViewForPoint(const gfx::Point& point) const { | |
| 262 ViewVector::const_reverse_iterator it = children_.rbegin(); | |
| 263 for (; it != children_.rend(); ++it) { | |
| 264 View* child = *it; | |
| 265 if (!child->visible()) | |
| 266 continue; | |
| 267 | |
| 268 gfx::Point point_in_child_coords(point); | |
| 269 View::ConvertPointToView(const_cast<View*>(this), child, | |
| 270 &point_in_child_coords); | |
| 271 if (child->HitTest(point_in_child_coords)) | |
| 272 return child->GetViewForPoint(point_in_child_coords); | |
| 273 } | |
| 274 return const_cast<View*>(this); | |
| 275 } | |
| 276 | |
| 277 bool View::HitTest(const gfx::Point& point) const { | |
| 278 // TODO(beng): Hit test mask support. | |
| 279 return GetContentsBounds().Contains(point); | |
|
sky
2011/02/01 18:56:22
I think the border should be considered part of th
| |
| 280 } | |
| 281 | |
| 282 View* View::GetViewById(int id) const { | |
| 283 if (id_ == id) | |
| 284 return const_cast<View*>(this); | |
| 285 ViewVector::const_iterator it = children_.begin(); | |
| 286 for (; it != children_.end(); ++it) { | |
| 287 View* view = (*it)->GetViewById(id); | |
| 288 if (view) | |
| 289 return view; | |
| 290 } | |
| 291 return NULL; | |
| 292 } | |
| 293 | |
| 294 void View::GetViewsWithGroup(int group, ViewVector* vec) const { | |
| 295 if (group_ == group) | |
| 296 vec->push_back(const_cast<View*>(this)); | |
| 297 ViewVector::const_iterator it = children_.begin(); | |
| 298 for (; it != children_.end(); ++it) | |
| 299 (*it)->GetViewsWithGroup(group, vec); | |
| 300 } | |
| 301 | |
| 302 void View::OnViewAdded(View* parent, View* child) { | |
| 303 } | |
| 304 | |
| 305 void View::OnViewRemoved(View* parent, View* child) { | |
| 306 } | |
| 307 | |
| 308 void View::OnViewAddedToWidget() { | |
| 309 } | |
| 310 | |
| 311 void View::OnViewRemovedFromWidget() { | |
| 312 } | |
| 313 | |
| 314 // Accelerators ---------------------------------------------------------------- | |
| 315 | |
| 316 void View::AddAccelerator(const Accelerator& accelerator) { | |
| 317 } | |
| 318 | |
| 319 void View::RemoveAccelerator(const Accelerator& accelerator) { | |
| 320 } | |
| 321 | |
| 322 void View::RemoveAllAccelerators() { | |
| 323 } | |
| 324 | |
| 325 bool View::OnAcceleratorPressed(const Accelerator& accelerator) { | |
| 326 return false; | |
| 327 } | |
| 328 | |
| 329 // Focus ----------------------------------------------------------------------- | |
| 330 | |
| 331 FocusManager* View::GetFocusManager() const { | |
| 332 return NULL; | |
| 333 } | |
| 334 | |
| 335 FocusTraversable* View::GetFocusTraversable() const { | |
| 336 return NULL; | |
| 337 } | |
| 338 | |
| 339 View* View::GetNextFocusableView() const { | |
| 340 return NULL; | |
| 341 } | |
| 342 | |
| 343 View* View::GetPreviousFocusableView() const { | |
| 344 return NULL; | |
| 345 } | |
| 346 | |
| 347 bool View::SkipDefaultKeyEventProcessing(const KeyEvent& event) const { | |
| 348 return false; | |
| 349 } | |
| 350 | |
| 351 bool View::IsFocusable() const { | |
| 352 return false; | |
| 353 } | |
| 354 | |
| 355 bool View::HasFocus() const { | |
| 356 return false; | |
| 357 } | |
| 358 | |
| 359 void View::RequestFocus() { | |
| 360 } | |
| 361 | |
| 362 void View::OnFocus(/* const FocusEvent& event */) { | |
| 363 } | |
| 364 | |
| 365 void View::OnBlur() { | |
| 366 } | |
| 367 | |
| 368 // Input ----------------------------------------------------------------------- | |
| 369 | |
| 370 bool View::OnKeyPressed(const KeyEvent& event) { | |
| 371 return true; | |
| 372 } | |
| 373 | |
| 374 bool View::OnKeyReleased(const KeyEvent& event) { | |
| 375 return true; | |
| 376 } | |
| 377 | |
| 378 bool View::OnMouseWheel(const MouseWheelEvent& event) { | |
| 379 return true; | |
| 380 } | |
| 381 | |
| 382 bool View::OnMousePressed(const MouseEvent& event) { | |
| 383 return true; | |
| 384 } | |
| 385 | |
| 386 bool View::OnMouseDragged(const MouseEvent& event) { | |
| 387 return true; | |
| 388 } | |
| 389 | |
| 390 void View::OnMouseReleased(const MouseEvent& event) { | |
| 391 | |
| 392 } | |
| 393 | |
| 394 void View::OnMouseCaptureLost() { | |
| 395 | |
| 396 } | |
| 397 | |
| 398 void View::OnMouseMoved(const MouseEvent& event) { | |
| 399 | |
| 400 } | |
| 401 | |
| 402 void View::OnMouseEntered(const MouseEvent& event) { | |
| 403 | |
| 404 } | |
| 405 | |
| 406 void View::OnMouseExited(const MouseEvent& event) { | |
| 407 | |
| 408 } | |
| 409 | |
| 410 gfx::NativeCursor View::GetCursorForPoint(const gfx::Point& point) { | |
| 411 return NULL; | |
| 412 } | |
| 413 | |
| 414 // Painting -------------------------------------------------------------------- | |
| 415 | |
| 416 void View::Invalidate() { | |
| 417 InvalidateRect(gfx::Rect(0, 0, width(), height())); | |
| 418 } | |
| 419 | |
| 420 void View::InvalidateRect(const gfx::Rect& invalid_rect) { | |
| 421 if (!visible_) | |
| 422 return; | |
| 423 | |
| 424 if (parent_) { | |
| 425 gfx::Rect r = invalid_rect; | |
| 426 r.Offset(bounds_.origin()); | |
| 427 parent_->InvalidateRect(r); | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 void View::Paint(gfx::Canvas* canvas) { | |
|
sky
2011/02/01 18:56:22
Because the canvas is not in the child coordinates
| |
| 432 // Invisible views are not painted. | |
| 433 if (!visible_) | |
| 434 return; | |
| 435 | |
| 436 ScopedCanvasState canvas_state(canvas); | |
| 437 if (canvas->ClipRectInt(x(), y(), width(), height())) { | |
| 438 canvas->TranslateInt(x(), y()); | |
| 439 // TODO(beng): RTL | |
| 440 ScopedCanvasState canvas_state(canvas); | |
|
sky
2011/02/01 18:56:22
Don't you need a different name than on line 436?
| |
| 441 OnPaint(canvas); | |
| 442 PaintChildren(canvas); | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 void View::PaintChildren(gfx::Canvas* canvas) { | |
| 447 // TODO(beng): use for_each. | |
| 448 // std::for_each(children_.begin(), children_.end(), | |
| 449 // std::bind2nd(std::mem_fun_ref(&View::Paint), canvas)); | |
| 450 ViewVector::iterator it = children_.begin(); | |
| 451 for (; it != children_.end(); ++it) | |
| 452 (*it)->Paint(canvas); | |
| 453 } | |
| 454 | |
| 455 void View::OnPaint(gfx::Canvas* canvas) { | |
| 456 OnPaintBackground(canvas); | |
| 457 OnPaintFocusBorder(canvas); | |
| 458 OnPaintBorder(canvas); | |
| 459 } | |
| 460 | |
| 461 void View::OnPaintBackground(gfx::Canvas* canvas) { | |
| 462 } | |
| 463 | |
| 464 void View::OnPaintBorder(gfx::Canvas* canvas) { | |
| 465 if (border_.get()) | |
| 466 border_->Paint(const_cast<const View*>(this), canvas); | |
| 467 } | |
| 468 | |
| 469 void View::OnPaintFocusBorder(gfx::Canvas* canvas) { | |
| 470 } | |
| 471 | |
| 472 // Resources ------------------------------------------------------------------- | |
| 473 | |
| 474 ThemeProvider* View::GetThemeProvider() const { | |
| 475 Widget* widget = GetWidget(); | |
| 476 return widget ? widget->GetThemeProvider() : NULL; | |
| 477 } | |
| 478 | |
| 479 //////////////////////////////////////////////////////////////////////////////// | |
| 480 // View, private: | |
| 481 | |
| 482 void View::DragInfo::Reset() { | |
| 483 possible_drag = false; | |
| 484 press_point = gfx::Point(); | |
| 485 } | |
| 486 | |
| 487 void View::DragInfo::PossibleDrag(const gfx::Point& point) { | |
| 488 possible_drag = true; | |
| 489 press_point = point; | |
| 490 } | |
| 491 | |
| 492 // Drag & Drop ----------------------------------------------------------------- | |
| 493 | |
| 494 int View::GetDragOperations(const gfx::Point& point) { | |
| 495 return drag_controller_ ? | |
| 496 drag_controller_->GetDragOperations(const_cast<View*>(this), point) : | |
| 497 DragDropTypes::DRAG_NONE; | |
| 498 } | |
| 499 | |
| 500 void View::WriteDragData(const gfx::Point& point, OSExchangeData* data) { | |
| 501 drag_controller_->WriteDragData(this, point, data); | |
| 502 } | |
| 503 | |
| 504 void View::StartShellDrag(const MouseEvent& event, | |
|
sky
2011/02/01 18:56:22
How come you named this with 'shell'? Why not just
Ben Goodger (Google)
2011/02/01 20:04:57
These methods are for initiating and dealing with
| |
| 505 const gfx::Point& press_point) { | |
| 506 // TODO(beng): system stuff. | |
| 507 } | |
| 508 | |
| 509 // RootView API ---------------------------------------------------------------- | |
| 510 | |
| 511 bool View::MousePressed(const MouseEvent& event, DragInfo* drag_info) { | |
| 512 bool handled = OnMousePressed(event); | |
| 513 if (!enabled_) | |
|
sky
2011/02/01 18:56:22
This crashes if 'this' is deleted in handling OnMo
Ben Goodger (Google)
2011/02/01 20:04:57
I added a TODO... I do have to wonder if this is a
| |
| 514 return handled; | |
| 515 | |
| 516 int drag_operations = | |
| 517 enabled_ && event.IsOnlyLeftMouseButton() && HitTest(event.location()) ? | |
| 518 GetDragOperations(event.location()) : DragDropTypes::DRAG_NONE; | |
| 519 if (drag_operations != DragDropTypes::DRAG_NONE) { | |
| 520 drag_info->PossibleDrag(event.location()); | |
| 521 return true; | |
| 522 } | |
| 523 bool has_context_menu = event.IsRightMouseButton() ? | |
| 524 !!context_menu_controller_ : NULL; | |
| 525 return has_context_menu || handled; | |
| 526 } | |
| 527 | |
| 528 bool View::MouseDragged(const MouseEvent& event, DragInfo* drag_info) { | |
| 529 if (drag_info->possible_drag && | |
| 530 ExceededDragThreshold(drag_info->press_point, event.location())) { | |
| 531 if (!drag_controller_ || | |
| 532 drag_controller_->CanStartDrag(this, drag_info->press_point, | |
| 533 event.location())) { | |
| 534 StartShellDrag(event, drag_info->press_point); | |
| 535 } | |
| 536 } else { | |
| 537 if (OnMouseDragged(event)) | |
| 538 return true; | |
| 539 } | |
| 540 return !!context_menu_controller_ || drag_info->possible_drag; | |
|
sky
2011/02/01 18:56:22
This crashes if 'this' is deleted in handling OnMo
| |
| 541 } | |
| 542 | |
| 543 void View::MouseReleased(const MouseEvent& event) { | |
| 544 OnMouseReleased(event); | |
| 545 if (context_menu_controller_ && event.IsOnlyRightMouseButton()) { | |
|
sky
2011/02/01 18:56:22
This crashes if 'this' is deleted in handling OnMo
| |
| 546 gfx::Point location(event.location()); | |
| 547 if (HitTest(location)) { | |
| 548 ConvertPointToScreen(this, &location); | |
| 549 context_menu_controller_->ShowContextMenu(this, location, true); | |
| 550 } | |
| 551 } | |
| 552 } | |
| 553 | |
| 554 // Tree operations ------------------------------------------------------------- | |
| 555 | |
| 556 void View::NotifyHierarchyChanged(View* parent, View* child, bool is_add) { | |
| 557 // Notify the child. Note that we call GetWidget() on the parent, not the | |
| 558 // child, since this method is called after the child is already removed from | |
| 559 // the hierarchy when |is_add| is false and so child->GetWidget() will always | |
| 560 // return NULL. | |
| 561 bool has_widget = parent->GetWidget() != NULL; | |
| 562 CallViewNotification(child, parent, child, is_add, has_widget); | |
| 563 | |
| 564 // Notify the hierarchy up. | |
| 565 NotifyHierarchyChangedUp(parent, child, is_add); | |
| 566 | |
| 567 // Notify the hierarchy down. | |
| 568 if (!is_add) { | |
| 569 // Because |child| has already been removed from |parent|'s child list, we | |
| 570 // need to notify its hierarchy manually. | |
| 571 child->NotifyHierarchyChangedDown(parent, child, is_add, has_widget); | |
| 572 } | |
| 573 NotifyHierarchyChangedDown(parent, child, is_add, has_widget); | |
| 574 } | |
| 575 | |
| 576 void View::NotifyHierarchyChangedUp(View* parent, View* child, bool is_add) { | |
| 577 for (View* v = parent; v; v = v->parent()) { | |
| 578 if (is_add) | |
| 579 v->OnViewAdded(parent, child); | |
| 580 else | |
| 581 v->OnViewRemoved(parent, child); | |
| 582 } | |
| 583 } | |
| 584 | |
| 585 void View::NotifyHierarchyChangedDown(View* parent, View* child, bool is_add, | |
| 586 bool has_widget) { | |
| 587 ViewVector::iterator it = children_.begin(); | |
| 588 for (; it != children_.end(); ++it) { | |
| 589 CallViewNotification(*it, parent, child, is_add, has_widget); | |
| 590 (*it)->NotifyHierarchyChangedDown(parent, child, is_add, has_widget); | |
| 591 } | |
| 592 } | |
| 593 | |
| 594 void View::CallViewNotification(View* target, | |
| 595 View* parent, | |
| 596 View* child, | |
| 597 bool is_add, | |
| 598 bool has_widget) { | |
| 599 if (is_add) { | |
| 600 target->OnViewAdded(parent, child); | |
| 601 if (has_widget) | |
| 602 target->OnViewAddedToWidget(); | |
| 603 } else { | |
| 604 target->OnViewRemoved(parent, child); | |
| 605 if (has_widget) | |
| 606 target->OnViewRemovedFromWidget(); | |
| 607 } | |
| 608 } | |
| 609 | |
| 610 } // namespace ui | |
| OLD | NEW |