| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/infobars/infobar_view.h" | 5 #include "chrome/browser/ui/views/infobars/infobar_view.h" |
| 6 | 6 |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
| 9 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h" | 9 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h" |
| 10 #include "chrome/browser/ui/views/infobars/infobar_background.h" | 10 #include "chrome/browser/ui/views/infobars/infobar_background.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 #include "ui/base/win/hwnd_util.h" | 34 #include "ui/base/win/hwnd_util.h" |
| 35 #include "ui/gfx/icon_util.h" | 35 #include "ui/gfx/icon_util.h" |
| 36 #endif | 36 #endif |
| 37 | 37 |
| 38 // static | 38 // static |
| 39 const int InfoBarView::kDefaultTargetHeight = 36; | 39 const int InfoBarView::kDefaultTargetHeight = 36; |
| 40 const int InfoBarView::kButtonButtonSpacing = 10; | 40 const int InfoBarView::kButtonButtonSpacing = 10; |
| 41 const int InfoBarView::kEndOfLabelSpacing = 16; | 41 const int InfoBarView::kEndOfLabelSpacing = 16; |
| 42 const int InfoBarView::kHorizontalPadding = 6; | 42 const int InfoBarView::kHorizontalPadding = 6; |
| 43 | 43 |
| 44 const int InfoBarView::kCurveWidth = 13; |
| 45 const int InfoBarView::kMaxIconWidth = 30; |
| 46 const int InfoBarView::kTabHeight = 9; |
| 47 const int InfoBarView::kTabIconPadding = 2; |
| 48 |
| 49 const int InfoBarView::kTabWidth = (kCurveWidth + kTabIconPadding) * 2 + |
| 50 kMaxIconWidth; |
| 51 |
| 44 InfoBarView::InfoBarView(InfoBarDelegate* delegate) | 52 InfoBarView::InfoBarView(InfoBarDelegate* delegate) |
| 45 : InfoBar(delegate), | 53 : InfoBar(delegate), |
| 46 container_(NULL), | 54 container_(NULL), |
| 47 delegate_(delegate), | 55 delegate_(delegate), |
| 48 icon_(NULL), | 56 icon_(NULL), |
| 49 close_button_(NULL), | 57 close_button_(NULL), |
| 50 ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))), | 58 ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))), |
| 51 ALLOW_THIS_IN_INITIALIZER_LIST(delete_factory_(this)), | 59 ALLOW_THIS_IN_INITIALIZER_LIST(delete_factory_(this)), |
| 52 target_height_(kDefaultTargetHeight) { | 60 target_height_(kDefaultTargetHeight), |
| 61 fill_path_(new SkPath), |
| 62 stroke_path_(new SkPath) { |
| 53 set_parent_owned(false); // InfoBar deletes itself at the appropriate time. | 63 set_parent_owned(false); // InfoBar deletes itself at the appropriate time. |
| 54 | 64 |
| 55 InfoBarDelegate::Type infobar_type = delegate->GetInfoBarType(); | 65 InfoBarDelegate::Type infobar_type = delegate->GetInfoBarType(); |
| 56 set_background(new InfoBarBackground(infobar_type)); | 66 set_background(new InfoBarBackground(infobar_type)); |
| 57 SetAccessibleName(l10n_util::GetStringUTF16( | 67 SetAccessibleName(l10n_util::GetStringUTF16( |
| 58 (infobar_type == InfoBarDelegate::WARNING_TYPE) ? | 68 (infobar_type == InfoBarDelegate::WARNING_TYPE) ? |
| 59 IDS_ACCNAME_INFOBAR_WARNING : IDS_ACCNAME_INFOBAR_PAGE_ACTION)); | 69 IDS_ACCNAME_INFOBAR_WARNING : IDS_ACCNAME_INFOBAR_PAGE_ACTION)); |
| 60 | 70 |
| 61 animation_->SetTweenType(ui::Tween::LINEAR); | 71 animation_->SetTweenType(ui::Tween::LINEAR); |
| 62 } | 72 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 82 restore_focus = false; | 92 restore_focus = false; |
| 83 #endif // defined(OS_WIN) | 93 #endif // defined(OS_WIN) |
| 84 DestroyFocusTracker(restore_focus); | 94 DestroyFocusTracker(restore_focus); |
| 85 animation_->Hide(); | 95 animation_->Hide(); |
| 86 } else { | 96 } else { |
| 87 animation_->Reset(0.0); | 97 animation_->Reset(0.0); |
| 88 Close(); | 98 Close(); |
| 89 } | 99 } |
| 90 } | 100 } |
| 91 | 101 |
| 92 void InfoBarView::PaintArrow(gfx::Canvas* canvas, | |
| 93 View* outer_view, | |
| 94 int arrow_center_x) { | |
| 95 gfx::Point infobar_top(0, y()); | |
| 96 ConvertPointToView(parent(), outer_view, &infobar_top); | |
| 97 int infobar_top_y = infobar_top.y(); | |
| 98 SkPoint gradient_points[2] = { | |
| 99 {SkIntToScalar(0), SkIntToScalar(infobar_top_y)}, | |
| 100 {SkIntToScalar(0), SkIntToScalar(infobar_top_y + target_height_)} | |
| 101 }; | |
| 102 InfoBarDelegate::Type infobar_type = delegate_->GetInfoBarType(); | |
| 103 SkColor gradient_colors[2] = { | |
| 104 InfoBarBackground::GetTopColor(infobar_type), | |
| 105 InfoBarBackground::GetBottomColor(infobar_type), | |
| 106 }; | |
| 107 SkShader* gradient_shader = SkGradientShader::CreateLinear(gradient_points, | |
| 108 gradient_colors, NULL, 2, SkShader::kMirror_TileMode); | |
| 109 SkPaint paint; | |
| 110 paint.setStrokeWidth(1); | |
| 111 paint.setStyle(SkPaint::kFill_Style); | |
| 112 paint.setShader(gradient_shader); | |
| 113 gradient_shader->unref(); | |
| 114 | |
| 115 // The size of the arrow (its height; also half its width). The | |
| 116 // arrow area is |arrow_size| ^ 2. By taking the square root of the | |
| 117 // animation value, we cause a linear animation of the area, which | |
| 118 // matches the perception of the animation of the InfoBar. | |
| 119 const int kArrowSize = 10; | |
| 120 int arrow_size = static_cast<int>(kArrowSize * | |
| 121 sqrt(animation_->GetCurrentValue())); | |
| 122 SkPath fill_path; | |
| 123 fill_path.moveTo(SkPoint::Make(SkIntToScalar(arrow_center_x - arrow_size), | |
| 124 SkIntToScalar(infobar_top_y))); | |
| 125 fill_path.rLineTo(SkIntToScalar(arrow_size), SkIntToScalar(-arrow_size)); | |
| 126 fill_path.rLineTo(SkIntToScalar(arrow_size), SkIntToScalar(arrow_size)); | |
| 127 SkPath border_path(fill_path); | |
| 128 fill_path.close(); | |
| 129 gfx::CanvasSkia* canvas_skia = canvas->AsCanvasSkia(); | |
| 130 canvas_skia->drawPath(fill_path, paint); | |
| 131 | |
| 132 // Fill and stroke have different opinions about how to treat paths. Because | |
| 133 // in Skia integral coordinates represent pixel boundaries, offsetting the | |
| 134 // path makes it go exactly through pixel centers; this results in lines that | |
| 135 // are exactly where we expect, instead of having odd "off by one" issues. | |
| 136 // Were we to do this for |fill_path|, however, which tries to fill "inside" | |
| 137 // the path (using some questionable math), we'd get a fill at a very | |
| 138 // different place than we'd want. | |
| 139 border_path.offset(SK_ScalarHalf, SK_ScalarHalf); | |
| 140 paint.setShader(NULL); | |
| 141 paint.setColor(SkColorSetA(ResourceBundle::toolbar_separator_color, | |
| 142 SkColorGetA(gradient_colors[0]))); | |
| 143 paint.setStyle(SkPaint::kStroke_Style); | |
| 144 canvas_skia->drawPath(border_path, paint); | |
| 145 } | |
| 146 | |
| 147 InfoBarView::~InfoBarView() { | 102 InfoBarView::~InfoBarView() { |
| 148 } | 103 } |
| 149 | 104 |
| 150 // static | 105 // static |
| 151 views::Label* InfoBarView::CreateLabel(const string16& text) { | 106 views::Label* InfoBarView::CreateLabel(const string16& text) { |
| 152 views::Label* label = new views::Label(UTF16ToWideHack(text), | 107 views::Label* label = new views::Label(UTF16ToWideHack(text), |
| 153 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont)); | 108 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont)); |
| 154 label->SetColor(SK_ColorBLACK); | 109 label->SetColor(SK_ColorBLACK); |
| 155 label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | 110 label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| 156 return label; | 111 return label; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 gfx::Size(GetSystemMetrics(SM_CXSMICON), | 179 gfx::Size(GetSystemMetrics(SM_CXSMICON), |
| 225 GetSystemMetrics(SM_CYSMICON)))); | 180 GetSystemMetrics(SM_CYSMICON)))); |
| 226 } | 181 } |
| 227 #endif | 182 #endif |
| 228 return text_button; | 183 return text_button; |
| 229 } | 184 } |
| 230 | 185 |
| 231 void InfoBarView::Layout() { | 186 void InfoBarView::Layout() { |
| 232 int start_x = kHorizontalPadding; | 187 int start_x = kHorizontalPadding; |
| 233 if (icon_ != NULL) { | 188 if (icon_ != NULL) { |
| 189 // Center the icon horizontally within the tab, and vertically between the |
| 190 // entire height (tab + bar). |
| 234 gfx::Size icon_size = icon_->GetPreferredSize(); | 191 gfx::Size icon_size = icon_->GetPreferredSize(); |
| 235 icon_->SetBounds(start_x, OffsetY(icon_size), icon_size.width(), | 192 int center_x = std::max((kTabWidth - icon_size.width()) / 2, 0); |
| 236 icon_size.height()); | 193 int full_height = target_height_ + kTabHeight; |
| 194 |
| 195 // This duplicates OffsetY except centered within the entire height (tab + |
| 196 // bar) instead of just within the bar. |
| 197 int offset_y = |
| 198 std::max((full_height - icon_size.height()) / 2, 0) - |
| 199 (full_height - height()); |
| 200 icon_->SetBounds(center_x, offset_y, icon_size.width(), icon_size.height()); |
| 237 start_x += icon_->bounds().right(); | 201 start_x += icon_->bounds().right(); |
| 238 } | 202 } |
| 239 | 203 |
| 240 gfx::Size button_size = close_button_->GetPreferredSize(); | 204 gfx::Size button_size = close_button_->GetPreferredSize(); |
| 241 close_button_->SetBounds(std::max(start_x + ContentMinimumWidth(), | 205 close_button_->SetBounds(std::max(start_x + ContentMinimumWidth(), |
| 242 width() - kHorizontalPadding - button_size.width()), | 206 width() - kHorizontalPadding - button_size.width()), |
| 243 OffsetY(button_size), button_size.width(), button_size.height()); | 207 OffsetY(button_size), button_size.width(), button_size.height()); |
| 244 } | 208 } |
| 245 | 209 |
| 246 void InfoBarView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { | 210 void InfoBarView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 | 264 |
| 301 // For accessibility, ensure the close button is the last child view. | 265 // For accessibility, ensure the close button is the last child view. |
| 302 if ((close_button_ != NULL) && (parent == this) && (child != close_button_) && | 266 if ((close_button_ != NULL) && (parent == this) && (child != close_button_) && |
| 303 (close_button_->parent() == this) && | 267 (close_button_->parent() == this) && |
| 304 (GetChildViewAt(child_count() - 1) != close_button_)) { | 268 (GetChildViewAt(child_count() - 1) != close_button_)) { |
| 305 RemoveChildView(close_button_); | 269 RemoveChildView(close_button_); |
| 306 AddChildView(close_button_); | 270 AddChildView(close_button_); |
| 307 } | 271 } |
| 308 } | 272 } |
| 309 | 273 |
| 274 void InfoBarView::PaintChildren(gfx::Canvas* canvas) { |
| 275 canvas->Save(); |
| 276 |
| 277 // TODO(scr): This really should be the |fill_path_|, but the clipPath seems |
| 278 // broken on non-Windows platforms (crbug.com/75154). For now, just clip to |
| 279 // the bar bounds. |
| 280 // |
| 281 // gfx::CanvasSkia* canvas_skia = canvas->AsCanvasSkia(); |
| 282 // canvas_skia->clipPath(*fill_path_); |
| 283 int tab_height = AnimatedTabHeight(); |
| 284 int bar_height = AnimatedBarHeight(); |
| 285 DCHECK_EQ(tab_height + bar_height, height()) |
| 286 << "Animation progressed between OnBoundsChanged & PaintChildren."; |
| 287 canvas->ClipRectInt(0, tab_height, width(), bar_height); |
| 288 |
| 289 views::View::PaintChildren(canvas); |
| 290 canvas->Restore(); |
| 291 } |
| 292 |
| 310 void InfoBarView::ButtonPressed(views::Button* sender, | 293 void InfoBarView::ButtonPressed(views::Button* sender, |
| 311 const views::Event& event) { | 294 const views::Event& event) { |
| 312 if (sender == close_button_) { | 295 if (sender == close_button_) { |
| 313 if (delegate_) | 296 if (delegate_) |
| 314 delegate_->InfoBarDismissed(); | 297 delegate_->InfoBarDismissed(); |
| 315 RemoveInfoBar(); | 298 RemoveInfoBar(); |
| 316 } | 299 } |
| 317 } | 300 } |
| 318 | 301 |
| 319 void InfoBarView::AnimationProgressed(const ui::Animation* animation) { | 302 void InfoBarView::AnimationProgressed(const ui::Animation* animation) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 341 int InfoBarView::EndX() const { | 324 int InfoBarView::EndX() const { |
| 342 const int kCloseButtonSpacing = 12; | 325 const int kCloseButtonSpacing = 12; |
| 343 return close_button_->x() - kCloseButtonSpacing; | 326 return close_button_->x() - kCloseButtonSpacing; |
| 344 } | 327 } |
| 345 | 328 |
| 346 int InfoBarView::CenterY(const gfx::Size prefsize) const { | 329 int InfoBarView::CenterY(const gfx::Size prefsize) const { |
| 347 return std::max((target_height_ - prefsize.height()) / 2, 0); | 330 return std::max((target_height_ - prefsize.height()) / 2, 0); |
| 348 } | 331 } |
| 349 | 332 |
| 350 int InfoBarView::OffsetY(const gfx::Size prefsize) const { | 333 int InfoBarView::OffsetY(const gfx::Size prefsize) const { |
| 351 return CenterY(prefsize) - (target_height_ - height()); | 334 return CenterY(prefsize) + AnimatedTabHeight() - |
| 335 (target_height_ - AnimatedBarHeight()); |
| 336 } |
| 337 |
| 338 int InfoBarView::AnimatedTabHeight() const { |
| 339 return static_cast<int>(kTabHeight * animation_->GetCurrentValue()); |
| 340 } |
| 341 |
| 342 int InfoBarView::AnimatedBarHeight() const { |
| 343 return static_cast<int>(target_height_ * animation_->GetCurrentValue()); |
| 352 } | 344 } |
| 353 | 345 |
| 354 AccessibilityTypes::Role InfoBarView::GetAccessibleRole() { | 346 AccessibilityTypes::Role InfoBarView::GetAccessibleRole() { |
| 355 return AccessibilityTypes::ROLE_ALERT; | 347 return AccessibilityTypes::ROLE_ALERT; |
| 356 } | 348 } |
| 357 | 349 |
| 358 gfx::Size InfoBarView::GetPreferredSize() { | 350 gfx::Size InfoBarView::GetPreferredSize() { |
| 359 return gfx::Size(0, | 351 return gfx::Size(0, AnimatedTabHeight() + AnimatedBarHeight()); |
| 360 static_cast<int>(target_height_ * animation_->GetCurrentValue())); | 352 } |
| 353 |
| 354 void InfoBarView::OnBoundsChanged() { |
| 355 views::View::OnBoundsChanged(); |
| 356 int tab_height = AnimatedTabHeight(); |
| 357 int bar_height = AnimatedBarHeight(); |
| 358 int divider_y = tab_height - 1; |
| 359 DCHECK_EQ(tab_height + bar_height, height()) |
| 360 << "Animation progressed between Layout & OnBoundsChanged."; |
| 361 |
| 362 int mirrored_x = GetMirroredXWithWidthInView(0, kTabWidth); |
| 363 stroke_path_->rewind(); |
| 364 fill_path_->rewind(); |
| 365 |
| 366 if (tab_height) { |
| 367 stroke_path_->moveTo(SkIntToScalar(mirrored_x), |
| 368 SkIntToScalar(divider_y)); |
| 369 stroke_path_->rCubicTo( |
| 370 SkScalarDiv(kCurveWidth, 2), 0.0, |
| 371 SkScalarDiv(kCurveWidth, 2), |
| 372 SkIntToScalar(-divider_y), |
| 373 SkIntToScalar(kCurveWidth), |
| 374 SkIntToScalar(-divider_y)); |
| 375 stroke_path_->rLineTo(SkScalarMulAdd(kTabIconPadding, 2, kMaxIconWidth), |
| 376 0.0); |
| 377 stroke_path_->rCubicTo( |
| 378 SkScalarDiv(kCurveWidth, 2), 0.0, |
| 379 SkScalarDiv(kCurveWidth, 2), |
| 380 SkIntToScalar(divider_y), |
| 381 SkIntToScalar(kCurveWidth), |
| 382 SkIntToScalar(divider_y)); |
| 383 |
| 384 // Create the fill portion of the tab. Because the fill is inside the |
| 385 // bounds and will not cover the separator, we need to extend downward by a |
| 386 // pixel before closing. |
| 387 *fill_path_ = *stroke_path_; |
| 388 fill_path_->rLineTo(0.0, 1.0); |
| 389 fill_path_->rLineTo(-SkIntToScalar(kTabWidth), 0.0); |
| 390 fill_path_->close(); |
| 391 |
| 392 // Fill and stroke have different opinions about how to treat paths. |
| 393 // Because in Skia integral coordinates represent pixel boundaries, |
| 394 // offsetting the path makes it go exactly through pixel centers; this |
| 395 // results in lines that are exactly where we expect, instead of having odd |
| 396 // "off by one" issues. Were we to do this for |fill_path|, however, which |
| 397 // tries to fill "inside" the path (using some questionable math), we'd get |
| 398 // a fill at a very different place than we'd want. |
| 399 stroke_path_->offset(SK_ScalarHalf, SK_ScalarHalf); |
| 400 } |
| 401 if (bar_height) { |
| 402 fill_path_->addRect(0.0, SkIntToScalar(tab_height), |
| 403 SkIntToScalar(width()), SkIntToScalar(height())); |
| 404 } |
| 361 } | 405 } |
| 362 | 406 |
| 363 void InfoBarView::FocusWillChange(View* focused_before, View* focused_now) { | 407 void InfoBarView::FocusWillChange(View* focused_before, View* focused_now) { |
| 364 // This will trigger some screen readers to read the entire contents of this | 408 // This will trigger some screen readers to read the entire contents of this |
| 365 // infobar. | 409 // infobar. |
| 366 if (focused_before && focused_now && !this->Contains(focused_before) && | 410 if (focused_before && focused_now && !this->Contains(focused_before) && |
| 367 this->Contains(focused_now)) | 411 this->Contains(focused_now)) |
| 368 NotifyAccessibilityEvent(AccessibilityTypes::EVENT_ALERT); | 412 NotifyAccessibilityEvent(AccessibilityTypes::EVENT_ALERT); |
| 369 } | 413 } |
| 370 | 414 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 395 // window), since this action can cause the delegate to destroy itself. | 439 // window), since this action can cause the delegate to destroy itself. |
| 396 if (delegate_) { | 440 if (delegate_) { |
| 397 delegate_->InfoBarClosed(); | 441 delegate_->InfoBarClosed(); |
| 398 delegate_ = NULL; | 442 delegate_ = NULL; |
| 399 } | 443 } |
| 400 } | 444 } |
| 401 | 445 |
| 402 void InfoBarView::DeleteSelf() { | 446 void InfoBarView::DeleteSelf() { |
| 403 delete this; | 447 delete this; |
| 404 } | 448 } |
| OLD | NEW |