1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be 3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file. 4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/infobars/infobar.h" 6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <cmath> 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/animation/slide_animation.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/tab_contents/infobar_delegate.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/infobars/infobar_container.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenInfoBar::InfoBar(InfoBarDelegate* delegate) 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : delegate_(delegate), 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen container_(NULL), 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))), 17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_height_(0), 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_target_height_(kDefaultArrowTargetHeight), 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_half_width_(0), 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bar_height_(0), 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bar_target_height_(kDefaultBarTargetHeight) { 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(delegate != NULL); 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen animation_->SetTweenType(ui::Tween::LINEAR); 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenInfoBar::~InfoBar() { 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::Show(bool animate) { 30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (animate) { 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen animation_->Show(); 32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen animation_->Reset(1.0); 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen AnimationEnded(NULL); 35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::Hide(bool animate) { 39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PlatformSpecificHide(animate); 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (animate) { 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen animation_->Hide(); 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen animation_->Reset(0.0); 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen AnimationEnded(NULL); 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::SetArrowTargetHeight(int height) { 49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK_LE(height, kMaximumArrowTargetHeight); 50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Once the closing animation starts, we ignore further requests to change the 51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // target height. 52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if ((arrow_target_height_ != height) && !animation()->IsClosing()) { 53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_target_height_ = height; 54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RecalculateHeights(false); 55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::AnimationProgressed(const ui::Animation* animation) { 59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RecalculateHeights(false); 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::RemoveInfoBar() { 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (container_) 64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen container_->RemoveDelegate(delegate_); 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::SetBarTargetHeight(int height) { 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (bar_target_height_ != height) { 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bar_target_height_ = height; 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RecalculateHeights(false); 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint InfoBar::OffsetY(const gfx::Size& prefsize) const { 75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return arrow_height_ + 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::max((bar_target_height_ - prefsize.height()) / 2, 0) - 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (bar_target_height_ - bar_height_); 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::AnimationEnded(const ui::Animation* animation) { 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // When the animation ends, we must ensure the container is notified even if 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // the heights haven't changed, lest it never get an "animation finished" 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // notification. (If the browser doesn't get this notification, it will not 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // bother to re-layout the content area for the new infobar size.) 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RecalculateHeights(true); 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MaybeDelete(); 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::RecalculateHeights(bool force_notify) { 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int old_arrow_height = arrow_height_; 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int old_bar_height = bar_height_; 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Find the desired arrow height/half-width. The arrow area is 94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // |arrow_height_| * |arrow_half_width_|. When the bar is opening or closing, 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // scaling each of these with the square root of the animation value causes a 96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // linear animation of the area, which matches the perception of the animation 97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // of the bar portion. 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen double scale_factor = sqrt(animation()->GetCurrentValue()); 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_height_ = static_cast<int>(arrow_target_height_ * scale_factor); 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (animation_->is_animating()) { 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_half_width_ = static_cast<int>(std::min(arrow_target_height_, 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen kMaximumArrowTargetHalfWidth) * scale_factor); 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // When the infobar is not animating (i.e. fully open), we set the 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // half-width to be proportionally the same distance between its default and 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // maximum values as the height is between its. 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_half_width_ = kDefaultArrowTargetHalfWidth + 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ((kMaximumArrowTargetHalfWidth - kDefaultArrowTargetHalfWidth) * 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ((arrow_height_ - kDefaultArrowTargetHeight) / 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (kMaximumArrowTargetHeight - kDefaultArrowTargetHeight))); 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Add pixels for the stroke, if the arrow is to be visible at all. Without 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // this, changing the arrow height from 0 to kSeparatorLineHeight would 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // produce no visible effect, because the stroke would paint atop the divider 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // line above the infobar. 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (arrow_height_) 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_height_ += kSeparatorLineHeight; 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bar_height_ = 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static_cast<int>(bar_target_height_ * animation()->GetCurrentValue()); 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Don't re-layout if nothing has changed, e.g. because the animation step was 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // not large enough to actually change the heights by at least a pixel. 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool heights_differ = 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (old_arrow_height != arrow_height_) || (old_bar_height != bar_height_); 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (heights_differ) 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PlatformSpecificOnHeightsRecalculated(); 128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (container_ && (heights_differ || force_notify)) 130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen container_->OnInfoBarStateChanged(animation_->is_animating()); 131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBar::MaybeDelete() { 134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (delegate_ && (animation_->GetCurrentValue() == 0.0)) { 135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (container_) 136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen container_->RemoveInfoBar(this); 137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Note that we only tell the delegate we're closed here, and not when we're 138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // simply destroyed (by virtue of a tab switch or being moved from window to 139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // window), since this action can cause the delegate to destroy itself. 140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate_->InfoBarClosed(); 141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate_ = NULL; 142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 144