// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/v2/public/view.h" #include <algorithm> #include "base/bind.h" #include "ui/compositor/layer_owner.h" #include "ui/v2/public/view_observer.h" #include "ui/v2/src/view_private.h" namespace v2 { enum StackDirection { STACK_ABOVE, STACK_BELOW }; void StackChildRelativeTo(View* parent, std::vector<View*>* children, View* child, View* other, StackDirection direction) { DCHECK_NE(child, other); DCHECK(child); DCHECK(other); DCHECK_EQ(parent, child->parent()); DCHECK_EQ(parent, other->parent()); // TODO(beng): Notify stacking changing. // TODO(beng): consult layout manager const size_t child_i = std::find(children->begin(), children->end(), child) - children->begin(); const size_t other_i = std::find(children->begin(), children->end(), other) - children->begin(); const size_t destination_i = direction == STACK_ABOVE ? (child_i < other_i ? other_i : other_i + 1) : (child_i < other_i ? other_i - 1 : other_i); children->erase(children->begin() + child_i); children->insert(children->begin() + destination_i, child); // TODO(beng): update layer. // TODO(beng): Notify stacking changed. } void NotifyViewTreeChangeAtReceiver( View* receiver, const ViewObserver::TreeChangeParams& params) { ViewObserver::TreeChangeParams local_params = params; local_params.receiver = receiver; FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(receiver).observers(), OnViewTreeChange(local_params)); } void NotifyViewTreeChangeUp(View* start_at, const ViewObserver::TreeChangeParams& params) { for (View* current = start_at; current; current = current->parent()) NotifyViewTreeChangeAtReceiver(current, params); } void NotifyViewTreeChangeDown(View* start_at, const ViewObserver::TreeChangeParams& params) { NotifyViewTreeChangeAtReceiver(start_at, params); View::Children::const_iterator it = start_at->children().begin(); for (; it != start_at->children().end(); ++it) NotifyViewTreeChangeDown(*it, params); } void NotifyViewTreeChange(const ViewObserver::TreeChangeParams& params) { NotifyViewTreeChangeDown(params.target, params); switch (params.phase) { case ViewObserver::DISPOSITION_CHANGING: if (params.old_parent) NotifyViewTreeChangeUp(params.old_parent, params); break; case ViewObserver::DISPOSITION_CHANGED: if (params.new_parent) NotifyViewTreeChangeUp(params.new_parent, params); break; default: NOTREACHED(); break; } } class ScopedTreeNotifier { public: ScopedTreeNotifier(View* target, View* old_parent, View* new_parent) { params_.target = target; params_.old_parent = old_parent; params_.new_parent = new_parent; NotifyViewTreeChange(params_); } ~ScopedTreeNotifier() { params_.phase = ViewObserver::DISPOSITION_CHANGED; NotifyViewTreeChange(params_); } private: ViewObserver::TreeChangeParams params_; DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier); }; void RemoveChildImpl(View* child, View::Children* children) { std::vector<View*>::iterator it = std::find(children->begin(), children->end(), child); if (it != children->end()) { children->erase(it); ViewPrivate(child).ClearParent(); } } class ViewLayerOwner : public ui::LayerOwner, public ui::LayerDelegate { public: explicit ViewLayerOwner(ui::Layer* layer) { layer_ = layer; } ~ViewLayerOwner() {} private: // Overridden from ui::LayerDelegate: virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { // TODO(beng): paint processor. } virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE { // TODO(beng): ??? } virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE { return base::Bind(&ViewLayerOwner::OnLayerBoundsChanged, base::Unretained(this)); } void OnLayerBoundsChanged() { // TODO(beng): ??? } DISALLOW_COPY_AND_ASSIGN(ViewLayerOwner); }; //////////////////////////////////////////////////////////////////////////////// // View, public: // Creation, configuration ----------------------------------------------------- View::View() : visible_(true), owned_by_parent_(true), parent_(NULL) { } View::~View() { FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroy(this, ViewObserver::DISPOSITION_CHANGING)); while (!children_.empty()) { View* child = children_.front(); if (child->owned_by_parent_) { delete child; // Deleting the child also removes it from our child list. DCHECK(std::find(children_.begin(), children_.end(), child) == children_.end()); } else { RemoveChild(child); } } if (parent_) parent_->RemoveChild(this); FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroy(this, ViewObserver::DISPOSITION_CHANGED)); } void View::AddObserver(ViewObserver* observer) { observers_.AddObserver(observer); } void View::RemoveObserver(ViewObserver* observer) { observers_.RemoveObserver(observer); } void View::SetPainter(Painter* painter) { painter_.reset(painter); } void View::SetLayout(Layout* layout) { layout_.reset(layout); } // Disposition ----------------------------------------------------------------- void View::SetBounds(const gfx::Rect& bounds) { gfx::Rect old_bounds = bounds_; // TODO(beng): consult layout manager bounds_ = bounds; // TODO(beng): update layer // TODO(beng): write tests for this where layoutmanager prevents a change // and no changed notification is sent. if (bounds_ != old_bounds) { FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewBoundsChanged(this, old_bounds, bounds_)); } } void View::SetVisible(bool visible) { FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChange(this, ViewObserver::DISPOSITION_CHANGING)); bool old_visible = visible_; // TODO(beng): consult layout manager visible_ = visible; // TODO(beng): update layer // TODO(beng): write tests for this where layoutmanager prevents a change // and no changed notification is sent. if (old_visible != visible_) { FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChange(this, ViewObserver::DISPOSITION_CHANGED)); } } // Tree ------------------------------------------------------------------------ void View::AddChild(View* child) { ScopedTreeNotifier notifier(child, child->parent(), this); if (child->parent()) RemoveChildImpl(child, &child->parent_->children_); children_.push_back(child); child->parent_ = this; } void View::RemoveChild(View* child) { DCHECK_EQ(this, child->parent()); ScopedTreeNotifier(child, this, NULL); RemoveChildImpl(child, &children_); } bool View::Contains(View* child) const { for (View* p = child->parent(); p; p = p->parent()) { if (p == this) return true; } return false; } void View::StackChildAtTop(View* child) { if (children_.size() <= 1 || child == children_.back()) return; // On top already. StackChildAbove(child, children_.back()); } void View::StackChildAtBottom(View* child) { if (children_.size() <= 1 || child == children_.front()) return; // On bottom already. StackChildBelow(child, children_.front()); } void View::StackChildAbove(View* child, View* other) { StackChildRelativeTo(this, &children_, child, other, STACK_ABOVE); } void View::StackChildBelow(View* child, View* other) { StackChildRelativeTo(this, &children_, child, other, STACK_BELOW); } // Layer ----------------------------------------------------------------------- const ui::Layer* View::layer() const { return layer_owner_.get() ? layer_owner_->layer() : NULL; } ui::Layer* View::layer() { return const_cast<ui::Layer*>(const_cast<const View*>(this)->layer()); } bool View::HasLayer() const { return !!layer(); } void View::CreateLayer(ui::LayerType layer_type) { layer_owner_.reset(new ViewLayerOwner(new ui::Layer(layer_type))); layer()->SetVisible(visible_); layer()->set_delegate(layer_owner_.get()); // TODO(beng): layer name? // TODO(beng): SetFillsBoundsOpaquely? } void View::DestroyLayer() { DCHECK(layer_owner_.get()); layer_owner_.reset(); } ui::Layer* View::AcquireLayer() { DCHECK(layer_owner_.get()); return layer_owner_->AcquireLayer(); } } // namespace v2