blob: 4185465d7e150863e567c1f2d90bdb691a43b9ca [file] [log] [blame]
// 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