Chromium Code Reviews| Index: athena/wm/overview_toolbar.cc |
| diff --git a/athena/wm/overview_toolbar.cc b/athena/wm/overview_toolbar.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6d32136a3c413bab19cde3be31641030e6f33abf |
| --- /dev/null |
| +++ b/athena/wm/overview_toolbar.cc |
| @@ -0,0 +1,196 @@ |
| +// Copyright 2014 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 "athena/wm/overview_toolbar.h" |
| + |
| +#include "athena/common/closure_animation_observer.h" |
| +#include "base/bind.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "base/time/time.h" |
| +#include "grit/athena_resources.h" |
| +#include "ui/aura/window.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| +#include "ui/compositor/layer.h" |
| +#include "ui/compositor/layer_delegate.h" |
| +#include "ui/compositor/scoped_layer_animation_settings.h" |
| +#include "ui/events/event.h" |
| +#include "ui/gfx/canvas.h" |
| +#include "ui/gfx/transform.h" |
| + |
| +namespace { |
| + |
| +const int kActionButtonImageSize = 54; |
| +const int kActionButtonTextSize = 20; |
| +const int kActionButtonPaddingFromRight = 32; |
| +} |
| + |
| +namespace athena { |
| + |
| +class ActionButton : public ui::LayerDelegate { |
|
Jun Mukai
2014/08/13 17:00:23
got confused, why this is a layer delegate rather
sadrul
2014/08/13 19:25:29
Pretty much, yeah. I considered making this a view
|
| + public: |
| + ActionButton(int resource_id, const std::string& label) |
| + : resource_id_(resource_id), label_(base::UTF8ToUTF16(label)) { |
| + layer_.reset(new ui::Layer(ui::LAYER_TEXTURED)); |
| + layer_->set_delegate(this); |
| + layer_->SetFillsBoundsOpaquely(false); |
| + layer_->SetVisible(true); |
| + layer_->SetOpacity(0); |
| + } |
| + |
| + virtual ~ActionButton() {} |
| + |
| + static void DestroyAfterFadeout(scoped_ptr<ActionButton> button) { |
| + ui::Layer* layer = button->layer(); |
| + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); |
| + settings.AddObserver(new ClosureAnimationObserver( |
| + base::Bind(&ActionButton::DestroyImmediately, base::Passed(&button)))); |
| + layer->SetOpacity(0); |
| + } |
| + |
| + void SetPosition(const gfx::Point& position) { |
| + layer_->SetBounds( |
| + gfx::Rect(position, |
| + gfx::Size(kActionButtonImageSize, |
| + kActionButtonImageSize + kActionButtonTextSize))); |
| + } |
| + |
| + ui::Layer* layer() { return layer_.get(); } |
| + |
| + private: |
| + static void DestroyImmediately(scoped_ptr<ActionButton> button) { |
| + button.reset(); |
| + } |
| + |
| + // ui::LayerDelegate: |
| + virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { |
| + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); |
| + canvas->DrawImageInt(*bundle.GetImageSkiaNamed(resource_id_), 0, 0); |
| + gfx::ShadowValues shadow; |
| + shadow.push_back(gfx::ShadowValue(gfx::Point(0, 1), 2, SK_ColorBLACK)); |
| + shadow.push_back(gfx::ShadowValue(gfx::Point(0, -1), 2, SK_ColorBLACK)); |
| + canvas->DrawStringRectWithShadows(label_, |
| + gfx::FontList(), |
| + SK_ColorWHITE, |
| + gfx::Rect(0, |
| + kActionButtonImageSize, |
| + kActionButtonImageSize, |
| + kActionButtonTextSize), |
| + 0, |
| + gfx::Canvas::TEXT_ALIGN_CENTER, |
| + shadow); |
| + } |
| + |
| + virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {} |
| + virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE { |
| + return base::Closure(); |
| + } |
| + |
| + int resource_id_; |
| + base::string16 label_; |
| + scoped_ptr<ui::Layer> layer_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ActionButton); |
| +}; |
| + |
| +OverviewToolbar::OverviewToolbar(aura::Window* container) |
| + : shown_(false), |
| + close_(new ActionButton(IDR_ATHENA_OVERVIEW_TRASH, "Close")), |
| + split_(new ActionButton(IDR_ATHENA_OVERVIEW_SPLIT, "Split")), |
| + current_action_(ACTION_TYPE_NONE), |
| + container_bounds_(container->bounds()) { |
| + const int kPaddingFromBottom = 200; |
| + const int kPaddingBetweenButtons = 200; |
| + |
| + int x = container_bounds_.right() - |
| + (kActionButtonPaddingFromRight + kActionButtonImageSize); |
| + int y = container_bounds_.bottom() - |
| + (kPaddingFromBottom + kActionButtonImageSize); |
| + split_->SetPosition(gfx::Point(x, y)); |
| + y -= kPaddingBetweenButtons; |
| + close_->SetPosition(gfx::Point(x, y)); |
| + |
| + container->layer()->Add(split_->layer()); |
| + container->layer()->Add(close_->layer()); |
| +} |
| + |
| +OverviewToolbar::~OverviewToolbar() { |
| + // If the buttons are visible, then fade them out, instead of destroying them |
| + // immediately. |
| + if (shown_) { |
| + ActionButton::DestroyAfterFadeout(split_.Pass()); |
| + ActionButton::DestroyAfterFadeout(close_.Pass()); |
| + } |
| +} |
| + |
| +OverviewToolbar::ActionType OverviewToolbar::GetHighlightAction( |
| + const ui::GestureEvent& event) const { |
| + if (IsEventOverButton(split_.get(), event)) |
| + return ACTION_TYPE_SPLIT; |
| + if (IsEventOverButton(close_.get(), event)) |
| + return ACTION_TYPE_CLOSE; |
| + return ACTION_TYPE_NONE; |
| +} |
| + |
| +void OverviewToolbar::SetHighlightAction(ActionType action) { |
| + if (current_action_ == action) |
| + return; |
| + current_action_ = action; |
| + if (!shown_) { |
| + ShowActionButtons(); |
| + } else { |
| + TransformButton(close_.get()); |
| + TransformButton(split_.get()); |
| + } |
| +} |
| + |
| +void OverviewToolbar::ShowActionButtons() { |
| + if (!shown_) |
| + ToggleActionButtonsVisibility(); |
| +} |
| + |
| +void OverviewToolbar::HideActionButtons() { |
| + if (shown_) |
| + ToggleActionButtonsVisibility(); |
| +} |
| + |
| +void OverviewToolbar::ToggleActionButtonsVisibility() { |
| + shown_ = !shown_; |
| + TransformButton(close_.get()); |
| + TransformButton(split_.get()); |
| +} |
| + |
| +bool OverviewToolbar::IsEventOverButton(ActionButton* button, |
| + const ui::GestureEvent& event) const { |
| + const int kBoundsInsetForTarget = 30; |
| + gfx::RectF bounds = button->layer()->bounds(); |
| + bounds.Inset(-kBoundsInsetForTarget, -kBoundsInsetForTarget); |
| + return bounds.Contains(event.location()); |
| +} |
| + |
| +gfx::Transform OverviewToolbar::ComputeTransformFor( |
| + ActionButton* button) const { |
| + if (!shown_) |
| + return gfx::Transform(); |
| + |
| + const float kHighlightScale = 1.5; |
| + bool button_is_highlighted = |
| + (current_action_ == ACTION_TYPE_CLOSE && button == close_.get()) || |
| + (current_action_ == ACTION_TYPE_SPLIT && button == split_.get()); |
| + gfx::Transform transform; |
| + if (button_is_highlighted) { |
| + transform.Translate(-kActionButtonImageSize * (kHighlightScale - 1) / 2, 0); |
| + transform.Scale(kHighlightScale, kHighlightScale); |
| + } |
| + return transform; |
| +} |
| + |
| +void OverviewToolbar::TransformButton(ActionButton* button) { |
| + ui::ScopedLayerAnimationSettings split_settings( |
| + button->layer()->GetAnimator()); |
| + split_settings.SetTweenType(gfx::Tween::SMOOTH_IN_OUT); |
| + button->layer()->SetTransform(ComputeTransformFor(button)); |
| + button->layer()->SetOpacity(shown_ ? 1 : 0); |
| +} |
| + |
| +} // namespace athena |