Chromium Code Reviews| Index: chrome/browser/ui/views/infobars/infobar_view.cc |
| diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc |
| index 97689bf769219a48fac8b86da42eafa025294c8b..6e1e3376a662a78344147d3e492339136d77efcf 100644 |
| --- a/chrome/browser/ui/views/infobars/infobar_view.cc |
| +++ b/chrome/browser/ui/views/infobars/infobar_view.cc |
| @@ -42,28 +42,42 @@ const int InfoBarView::kButtonButtonSpacing = 10; |
| const int InfoBarView::kEndOfLabelSpacing = 16; |
| const int InfoBarView::kHorizontalPadding = 6; |
| +const int InfoBarView::kCurveDistance = 13; |
| +const int InfoBarView::kIconWidth = 29; |
| +const int InfoBarView::kTabHeight = 9; |
| +const int InfoBarView::kTabPadding = 4; |
| + |
| +const int InfoBarView::kTabWidth = kCurveDistance * 2 + kIconWidth + |
| + kTabPadding; |
| + |
| InfoBarView::InfoBarView(InfoBarDelegate* delegate) |
| : InfoBar(delegate), |
| container_(NULL), |
| delegate_(delegate), |
| icon_(NULL), |
| close_button_(NULL), |
| - ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))), |
| + ALLOW_THIS_IN_INITIALIZER_LIST(tab_animation_(new ui::SlideAnimation(this))), |
|
Peter Kasting
2011/03/04 22:23:42
Nit: 80 columns (but this should go away when you
Sheridan Rawlins
2011/03/05 18:06:54
Done.
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(bar_animation_(new ui::SlideAnimation(this))), |
| ALLOW_THIS_IN_INITIALIZER_LIST(delete_factory_(this)), |
| - target_height_(kDefaultTargetHeight) { |
| + target_height_(kDefaultTargetHeight), |
| + stroke_path_(new SkPath), |
| + fill_path_(new SkPath), |
| + clip_path_(new SkPath) { |
| set_parent_owned(false); // InfoBar deletes itself at the appropriate time. |
| InfoBarDelegate::Type infobar_type = delegate->GetInfoBarType(); |
| set_background(new InfoBarBackground(infobar_type)); |
| - animation_->SetTweenType(ui::Tween::LINEAR); |
| + tab_animation_->SetTweenType(ui::Tween::LINEAR); |
| + bar_animation_->SetTweenType(ui::Tween::LINEAR); |
| } |
| void InfoBarView::Show(bool animate) { |
| if (animate) { |
| - animation_->Show(); |
| + AnimationShow(); |
| } else { |
| - animation_->Reset(1.0); |
| + AnimationReset(1.0); |
| + InvalidateLayout(); |
| if (container_) |
| container_->OnInfoBarAnimated(true); |
| } |
| @@ -80,9 +94,9 @@ void InfoBarView::Hide(bool animate) { |
| restore_focus = false; |
| #endif // defined(OS_WIN) |
| DestroyFocusTracker(restore_focus); |
| - animation_->Hide(); |
| + AnimationHide(); |
| } else { |
| - animation_->Reset(0.0); |
| + AnimationReset(0.0); |
| Close(); |
| } |
| } |
| @@ -100,61 +114,6 @@ void InfoBarView::Close() { |
| } |
| } |
| -void InfoBarView::PaintArrow(gfx::Canvas* canvas, |
| - View* outer_view, |
| - int arrow_center_x) { |
| - gfx::Point infobar_top(0, y()); |
| - ConvertPointToView(parent(), outer_view, &infobar_top); |
| - int infobar_top_y = infobar_top.y(); |
| - SkPoint gradient_points[2] = { |
| - {SkIntToScalar(0), SkIntToScalar(infobar_top_y)}, |
| - {SkIntToScalar(0), SkIntToScalar(infobar_top_y + target_height_)} |
| - }; |
| - InfoBarDelegate::Type infobar_type = delegate_->GetInfoBarType(); |
| - SkColor gradient_colors[2] = { |
| - InfoBarBackground::GetTopColor(infobar_type), |
| - InfoBarBackground::GetBottomColor(infobar_type), |
| - }; |
| - SkShader* gradient_shader = SkGradientShader::CreateLinear(gradient_points, |
| - gradient_colors, NULL, 2, SkShader::kMirror_TileMode); |
| - SkPaint paint; |
| - paint.setStrokeWidth(1); |
| - paint.setStyle(SkPaint::kFill_Style); |
| - paint.setShader(gradient_shader); |
| - gradient_shader->unref(); |
| - |
| - // The size of the arrow (its height; also half its width). The |
| - // arrow area is |arrow_size| ^ 2. By taking the square root of the |
| - // animation value, we cause a linear animation of the area, which |
| - // matches the perception of the animation of the InfoBar. |
| - const int kArrowSize = 10; |
| - int arrow_size = static_cast<int>(kArrowSize * |
| - sqrt(animation_->GetCurrentValue())); |
| - SkPath fill_path; |
| - fill_path.moveTo(SkPoint::Make(SkIntToScalar(arrow_center_x - arrow_size), |
| - SkIntToScalar(infobar_top_y))); |
| - fill_path.rLineTo(SkIntToScalar(arrow_size), SkIntToScalar(-arrow_size)); |
| - fill_path.rLineTo(SkIntToScalar(arrow_size), SkIntToScalar(arrow_size)); |
| - SkPath border_path(fill_path); |
| - fill_path.close(); |
| - gfx::CanvasSkia* canvas_skia = canvas->AsCanvasSkia(); |
| - canvas_skia->drawPath(fill_path, paint); |
| - |
| - // Fill and stroke have different opinions about how to treat paths. Because |
| - // in Skia integral coordinates represent pixel boundaries, offsetting the |
| - // path makes it go exactly through pixel centers; this results in lines that |
| - // are exactly where we expect, instead of having odd "off by one" issues. |
| - // Were we to do this for |fill_path|, however, which tries to fill "inside" |
| - // the path (using some questionable math), we'd get a fill at a very |
| - // different place than we'd want. |
| - border_path.offset(SK_ScalarHalf, SK_ScalarHalf); |
| - paint.setShader(NULL); |
| - paint.setColor(SkColorSetA(ResourceBundle::toolbar_separator_color, |
| - SkColorGetA(gradient_colors[0]))); |
| - paint.setStyle(SkPaint::kStroke_Style); |
| - canvas_skia->drawPath(border_path, paint); |
| -} |
| - |
| InfoBarView::~InfoBarView() { |
| } |
| @@ -241,10 +200,17 @@ views::TextButton* InfoBarView::CreateTextButton( |
| void InfoBarView::Layout() { |
| int start_x = kHorizontalPadding; |
| + |
|
Peter Kasting
2011/03/04 22:23:42
Nit: No blank line
Sheridan Rawlins
2011/03/05 18:06:54
Done.
|
| if (icon_ != NULL) { |
| + // Center the icon vertically and horizontally within the tab. |
| gfx::Size icon_size = icon_->GetPreferredSize(); |
| - icon_->SetBounds(start_x, OffsetY(icon_size), icon_size.width(), |
| - icon_size.height()); |
| + int center_x = std::max((kTabWidth - icon_size.width()) / 2, 0); |
| + int full_height = target_height_ + kTabHeight; |
| + int preferred_height = preferred_tab_height() + preferred_bar_height(); |
| + int center_y = |
| + std::max((full_height - icon_size.height()) / 2, 0) - |
| + (full_height - preferred_height); |
| + icon_->SetBounds(center_x, center_y, icon_size.width(), icon_size.height()); |
| start_x += icon_->bounds().right(); |
| } |
| @@ -300,7 +266,7 @@ void InfoBarView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { |
| // NULL our container_ pointer so that if Animation::Stop results in |
| // AnimationEnded being called, we do not try and delete ourselves twice. |
| container_ = NULL; |
| - animation_->Stop(); |
| + AnimationStop(); |
| // Finally, clean ourselves up when we're removed from the view hierarchy |
| // since no-one refers to us now. |
| MessageLoop::current()->PostTask(FROM_HERE, |
| @@ -319,6 +285,24 @@ void InfoBarView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { |
| } |
| } |
| +void InfoBarView::PaintChildren(gfx::Canvas* canvas) { |
| + canvas->Save(); |
| + |
| + // TODO(scr): This really should be the |clip_path_|, but the |
| + // clipPath seems broken. Try to get a reduction and file a bug |
| + // with skia. For now, just clip to the bar bounds. |
|
Peter Kasting
2011/03/04 22:23:42
Did you contact Mike Reed? He may be able to just
Sheridan Rawlins
2011/03/05 18:06:54
I definitely want to file a bug for this, but it s
|
| + // |
| + // gfx::CanvasSkia* canvas_skia = canvas->AsCanvasSkia(); |
| + // canvas_skia->clipPath(*clip_path_); |
| + int tab_height = preferred_tab_height(); |
| + int bar_height = preferred_bar_height(); |
| + DCHECK_EQ(tab_height + bar_height, height()); |
| + canvas->ClipRectInt(0, tab_height, width(), bar_height); |
| + |
| + views::View::PaintChildren(canvas); |
| + canvas->Restore(); |
| +} |
| + |
| void InfoBarView::ButtonPressed(views::Button* sender, |
| const views::Event& event) { |
| if (sender == close_button_) { |
| @@ -329,6 +313,9 @@ void InfoBarView::ButtonPressed(views::Button* sender, |
| } |
| void InfoBarView::AnimationProgressed(const ui::Animation* animation) { |
| + // If multiple infobars, the InfoBarContainer's bounds won't change |
| + // when only the bottom tab is animating. |
| + InvalidateLayout(); |
| if (container_) |
| container_->OnInfoBarAnimated(false); |
| } |
| @@ -360,7 +347,17 @@ int InfoBarView::CenterY(const gfx::Size prefsize) const { |
| } |
| int InfoBarView::OffsetY(const gfx::Size prefsize) const { |
| - return CenterY(prefsize) - (target_height_ - height()); |
| + return CenterY(prefsize) + preferred_tab_height() - (target_height_ - |
| + preferred_bar_height()); |
| +} |
| + |
| +int InfoBarView::preferred_tab_height() const { |
| + // TODO(scr): hookup tab_animation_ |
| + return static_cast<int>(kTabHeight * tab_animation_->GetCurrentValue()); |
| +} |
| + |
| +int InfoBarView::preferred_bar_height() const { |
| + return static_cast<int>(target_height_ * bar_animation_->GetCurrentValue()); |
| } |
| void InfoBarView::GetAccessibleState(ui::AccessibleViewState* state) { |
| @@ -371,8 +368,60 @@ void InfoBarView::GetAccessibleState(ui::AccessibleViewState* state) { |
| } |
| gfx::Size InfoBarView::GetPreferredSize() { |
| - return gfx::Size(0, |
| - static_cast<int>(target_height_ * animation_->GetCurrentValue())); |
| + return gfx::Size(0, preferred_tab_height() + preferred_bar_height()); |
| +} |
| + |
| +void InfoBarView::OnBoundsChanged() { |
| + views::View::OnBoundsChanged(); |
| + int tab_height = preferred_tab_height(); |
| + int bar_height = preferred_bar_height(); |
| + DCHECK_EQ(tab_height + bar_height, height()); |
| + |
| + // Fill and stroke have different opinions about how to treat paths. Because |
| + // in Skia integral coordinates represent pixel boundaries, offsetting the |
| + // path makes it go exactly through pixel centers; this results in lines that |
| + // are exactly where we expect, instead of having odd "off by one" issues. |
| + // Were we to do this for |fill_path|, however, which tries to fill "inside" |
| + // the path (using some questionable math), we'd get a fill at a very |
| + // different place than we'd want. |
| + int mirrored_x = GetMirroredXWithWidthInView(0, kTabWidth); |
| + stroke_path_->rewind(); |
| + if (tab_height) { |
| + stroke_path_->moveTo(SkIntToScalar(mirrored_x) + SK_ScalarHalf, |
|
Peter Kasting
2011/03/04 22:23:42
These offsets all seem wrong to me. It seems like
Sheridan Rawlins
2011/03/05 18:06:54
Ok. Instead of the SK_Scalar1, I added a kTabStro
|
| + SkIntToScalar(tab_height) - SK_ScalarHalf); |
| + stroke_path_->rCubicTo( |
| + SkScalarDiv(kCurveDistance, 2), 0.0, |
| + SkScalarDiv(kCurveDistance, 2), SK_Scalar1 - SkIntToScalar(tab_height), |
| + SkIntToScalar(kCurveDistance), SK_Scalar1 - SkIntToScalar(tab_height)); |
| + stroke_path_->rLineTo(SkIntToScalar(kTabPadding + kIconWidth), 0.0); |
| + stroke_path_->rCubicTo( |
| + SkScalarDiv(kCurveDistance, 2), 0.0, |
| + SkScalarDiv(kCurveDistance, 2), SkIntToScalar(tab_height) - SK_Scalar1, |
| + SkIntToScalar(kCurveDistance), SkIntToScalar(tab_height) - SK_Scalar1); |
| + } |
| + |
| + fill_path_->rewind(); |
| + if (tab_height + bar_height) { |
| + fill_path_->moveTo(SkIntToScalar(mirrored_x), SkIntToScalar(tab_height)); |
| + fill_path_->rCubicTo( |
| + SkScalarDiv(kCurveDistance, 2), 0.0, |
| + SkScalarDiv(kCurveDistance, 2), -SkIntToScalar(tab_height), |
| + SkIntToScalar(kCurveDistance), -SkIntToScalar(tab_height)); |
| + fill_path_->rLineTo(SkIntToScalar(kTabPadding + kIconWidth), 0.0); |
| + fill_path_->rCubicTo( |
| + SkScalarDiv(kCurveDistance, 2), 0.0, |
| + SkScalarDiv(kCurveDistance, 2), SkIntToScalar(tab_height), |
| + SkIntToScalar(kCurveDistance), SkIntToScalar(tab_height)); |
| + fill_path_->lineTo(SkIntToScalar(width()), SkIntToScalar(tab_height)); |
| + fill_path_->lineTo(SkIntToScalar(width()), |
| + SkIntToScalar(height())); |
| + fill_path_->lineTo(SkIntToScalar(0), SkIntToScalar(height())); |
| + fill_path_->lineTo(SkIntToScalar(0), SkIntToScalar(tab_height)); |
| + fill_path_->close(); |
| + } |
| + |
| + // Use the same clip path as the fill path. |
|
Peter Kasting
2011/03/04 22:23:42
Nit: We shouldn't even have |clip_path_|, then.
Sheridan Rawlins
2011/03/05 18:06:54
Done.
|
| + *clip_path_ = *fill_path_; |
| } |
| void InfoBarView::FocusWillChange(View* focused_before, View* focused_now) { |
| @@ -386,8 +435,37 @@ void InfoBarView::FocusWillChange(View* focused_before, View* focused_now) { |
| } |
| void InfoBarView::AnimationEnded(const ui::Animation* animation) { |
| - if (container_ && !animation_->IsShowing()) |
| - Close(); |
| + if (animation == bar_animation_.get()) { |
| + if (bar_animation_->IsShowing()) |
| + tab_animation_->Show(); |
| + else if (container_) |
| + Close(); |
| + } |
| + if (animation == tab_animation_.get()) { |
| + if (!tab_animation_->IsShowing()) |
| + bar_animation_->Hide(); |
| + } |
| +} |
| + |
| +void InfoBarView::AnimationReset(double value) { |
| + // Since we animate the bar first and then the tab, distribute the |
| + // value across the two animation objects. |
| + double double_value = value * 2.0; |
| + bar_animation_->Reset(std::min(double_value, 1.0)); |
| + tab_animation_->Reset(std::max(double_value - 1.0, 0.0)); |
| +} |
| + |
| +void InfoBarView::AnimationShow() { |
| + bar_animation_->Show(); |
| +} |
| + |
| +void InfoBarView::AnimationHide() { |
| + tab_animation_->Hide(); |
| +} |
| + |
| +void InfoBarView::AnimationStop() { |
| + tab_animation_->Stop(); |
| + bar_animation_->Stop(); |
| } |
| void InfoBarView::DestroyFocusTracker(bool restore_focus) { |