notification_view.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/views/notification_view.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/utf_string_conversions.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/ui_resources.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/accessibility/accessible_view_state.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/layout.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/text/text_elider.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/canvas.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/size.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/message_center.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/message_center_constants.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/message_center_switches.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/message_center_util.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification_types.h" 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/views/bounded_label.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/views/message_simple_view.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/button/image_button.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/image_view.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/label.h" 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/layout/box_layout.h" 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/layout/fill_layout.h" 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/widget/widget.h" 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Dimensions. 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kIconSize = message_center::kNotificationIconSize; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kLegacyIconSize = 40; 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kIconBottomPadding = 16; 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kTextLeftPadding = kIconSize + message_center::kIconToTextPadding; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kTextBottomPadding = 12; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTextRightPadding = 23; 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kItemTitleToMessagePadding = 3; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonHeight = 38; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonHorizontalPadding = 16; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonVecticalPadding = 0; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonIconTopPadding = 11; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonIconToTitlePadding = 16; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonTitleTopPadding = 0; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Line limits. 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kTitleLineLimit = 3; 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kMessageCollapsedLineLimit = 3; 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kMessageExpandedLineLimit = 7; 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Character limits: Displayed text will be subject to the line limits above, 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// but we also remove trailing characters from text to reduce processing cost. 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Character limit = pixels per line * line limit / min. pixels per character. 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kTitleCharacterLimit = 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center::kNotificationWidth * kTitleLineLimit / 4; 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kMessageCharacterLimit = 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center::kNotificationWidth * kMessageExpandedLineLimit / 3; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Notification colors. The text background colors below are used only to keep 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// view::Label from modifying the text color and will not actually be drawn. 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// See view::Label's RecalculateColors() for details. 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kRegularTextBackgroundColor = SK_ColorWHITE; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const SkColor kDimTextColor = SkColorSetRGB(102, 102, 102); 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const SkColor kDimTextBackgroundColor = SK_ColorWHITE; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kButtonSeparatorColor = SkColorSetRGB(234, 234, 234); 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const SkColor kHoveredButtonBackgroundColor = SkColorSetRGB(243, 243, 243); 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::Background* MakeBackground( 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkColor color = message_center::kNotificationBackgroundColor) { 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return views::Background::CreateSolidBackground(color); 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::Border* MakeEmptyBorder(int top, int left, int bottom, int right) { 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return views::Border::CreateEmptyBorder(top, left, bottom, right); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::Border* MakeTextBorder(int padding, int top, int bottom) { 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Split the padding between the top and the bottom, then add the extra space. 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return MakeEmptyBorder(padding / 2 + top, kTextLeftPadding, 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (padding + 1) / 2 + bottom, kTextRightPadding); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::Border* MakeSeparatorBorder(int top, int left, SkColor color) { 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return views::Border::CreateSolidSidedBorder(top, left, 0, 0, color); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Return true if and only if the image is null or has alpha. 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool HasAlpha(gfx::ImageSkia& image, views::Widget* widget) { 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Determine which bitmap to use. 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::ScaleFactor factor = ui::SCALE_FACTOR_100P; 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (widget) { 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) factor = ui::GetScaleFactorForNativeView(widget->GetNativeView()); 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (factor == ui::SCALE_FACTOR_NONE) 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) factor = ui::SCALE_FACTOR_100P; 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Extract that bitmap's alpha and look for a non-opaque pixel there. 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap bitmap = image.GetRepresentation(factor).sk_bitmap(); 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!bitmap.isNull()) { 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap alpha; 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) alpha.setConfig(SkBitmap::kA1_Config, bitmap.width(), bitmap.height(), 0); 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bitmap.extractAlpha(&alpha); 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int y = 0; y < bitmap.height(); ++y) { 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int x = 0; x < bitmap.width(); ++x) { 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (alpha.getColor(x, y) != SK_ColorBLACK) { 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If no opaque pixel was found, return false unless the bitmap is empty. 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return bitmap.isNull(); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ItemView //////////////////////////////////////////////////////////////////// 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ItemViews are responsible for drawing each list notification item's title and 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// message next to each other within a single column. 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ItemView : public views::View { 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ItemView(const message_center::NotificationItem& item); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~ItemView(); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void SetVisible(bool visible) OVERRIDE; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ItemView); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ItemView::ItemView(const message_center::NotificationItem& item) { 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 0, 0, kItemTitleToMessagePadding)); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::Label* title = new views::Label(item.title); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title->set_collapse_when_hidden(true); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title->SetElideBehavior(views::Label::ELIDE_AT_END); 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title->SetEnabledColor(message_center::kRegularTextColor); 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title->SetBackgroundColor(kRegularTextBackgroundColor); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(title); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::Label* message = new views::Label(item.message); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message->set_collapse_when_hidden(true); 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message->SetElideBehavior(views::Label::ELIDE_AT_END); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message->SetEnabledColor(kDimTextColor); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message->SetBackgroundColor(kDimTextBackgroundColor); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(message); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PreferredSizeChanged(); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaint(); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ItemView::~ItemView() { 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ItemView::SetVisible(bool visible) { 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::View::SetVisible(visible); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < child_count(); ++i) 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) child_at(i)->SetVisible(visible); 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ProportionalImageView /////////////////////////////////////////////////////// 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ProportionalImageViews center their images to preserve their proportion. 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ProportionalImageView : public views::View { 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProportionalImageView(const gfx::ImageSkia& image); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~ProportionalImageView(); 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Overridden from views::View: 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual gfx::Size GetPreferredSize() OVERRIDE; 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual int GetHeightForWidth(int width) OVERRIDE; 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size GetImageSizeForWidth(int width); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::ImageSkia image_; 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ProportionalImageView); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProportionalImageView::ProportionalImageView(const gfx::ImageSkia& image) 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : image_(image) { 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProportionalImageView::~ProportionalImageView() { 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size ProportionalImageView::GetPreferredSize() { 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size size = GetImageSizeForWidth(image_.width()); 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Size(size.width() + GetInsets().width(), 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size.height() + GetInsets().height()); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ProportionalImageView::GetHeightForWidth(int width) { 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetImageSizeForWidth(width).height(); 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProportionalImageView::OnPaint(gfx::Canvas* canvas) { 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::View::OnPaint(canvas); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size draw_size(GetImageSizeForWidth(width())); 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!draw_size.IsEmpty()) { 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect draw_bounds = GetContentsBounds(); 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) draw_bounds.ClampToCenteredSize(draw_size); 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size image_size(image_.size()); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (image_size == draw_size) { 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->DrawImageInt(image_, draw_bounds.x(), draw_bounds.y()); 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Resize case 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkPaint paint; 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) paint.setFilterBitmap(true); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->DrawImageInt(image_, 0, 0, 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) image_size.width(), image_size.height(), 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) draw_bounds.x(), draw_bounds.y(), 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) draw_size.width(), draw_size.height(), 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) true, paint); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size ProportionalImageView::GetImageSizeForWidth(int width) { 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size size = visible() ? image_.size() : gfx::Size(); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (width > 0 && !size.IsEmpty()) { 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double proportion = size.height() / (double) size.width(); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size.SetSize(width, std::max(0.5 + width * proportion, 1.0)); 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (size.height() > message_center::kNotificationMaximumImageHeight) { 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int height = message_center::kNotificationMaximumImageHeight; 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size.SetSize(std::max(0.5 + height / proportion, 1.0), height); 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return size; 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NotificationButton ////////////////////////////////////////////////////////// 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NotificationButtons render the action buttons of notifications. 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class NotificationButton : public views::CustomButton { 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotificationButton(views::ButtonListener* listener); 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~NotificationButton(); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void SetIcon(const gfx::ImageSkia& icon); 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void SetTitle(const string16& title); 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Overridden from views::View: 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual gfx::Size GetPreferredSize() OVERRIDE; 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual int GetHeightForWidth(int width) OVERRIDE; 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void OnFocus() OVERRIDE; 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE; 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Overridden from views::CustomButton: 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void StateChanged() OVERRIDE; 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::ImageView* icon_; 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::Label* title_; 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationButton::NotificationButton(views::ButtonListener* listener) 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : views::CustomButton(listener), 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_(NULL), 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_(NULL) { 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) set_focusable(true); 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) set_request_focus_on_press(false); 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kButtonHorizontalPadding, 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kButtonVecticalPadding, 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kButtonIconToTitlePadding)); 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationButton::~NotificationButton() { 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationButton::SetIcon(const gfx::ImageSkia& image) { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (icon_ != NULL) 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete icon_; // This removes the icon from this view's children. 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (image.isNull()) { 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_ = NULL; 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_ = new views::ImageView(); 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_->SetImageSize(gfx::Size(message_center::kNotificationButtonIconSize, 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_center::kNotificationButtonIconSize)); 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_->SetImage(image); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_->SetHorizontalAlignment(views::ImageView::LEADING); 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_->SetVerticalAlignment(views::ImageView::LEADING); 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) icon_->set_border(MakeEmptyBorder(kButtonIconTopPadding, 0, 0, 0)); 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildViewAt(icon_, 0); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationButton::SetTitle(const string16& title) { 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (title_ != NULL) 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete title_; // This removes the title from this view's children. 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (title.empty()) { 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_ = NULL; 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_ = new views::Label(title); 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_->SetElideBehavior(views::Label::ELIDE_AT_END); 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title_->SetEnabledColor(message_center::kRegularTextColor); 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_->SetBackgroundColor(kRegularTextBackgroundColor); 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title_->set_border(MakeEmptyBorder(kButtonTitleTopPadding, 0, 0, 0)); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(title_); 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 318b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) SetAccessibleName(title); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size NotificationButton::GetPreferredSize() { 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Size(message_center::kNotificationWidth, kButtonHeight); 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int NotificationButton::GetHeightForWidth(int width) { 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return kButtonHeight; 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NotificationButton::OnFocus() { 330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) views::CustomButton::OnFocus(); 331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScrollRectToVisible(GetLocalBounds()); 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NotificationButton::OnPaintFocusBorder(gfx::Canvas* canvas) { 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (HasFocus() && (focusable() || IsAccessibilityFocusable())) { 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3), 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center::kFocusBorderColor); 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NotificationButton::StateChanged() { 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (state() == STATE_HOVERED || state() == STATE_PRESSED) 343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) set_background(MakeBackground(kHoveredButtonBackgroundColor)); 344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else 345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) set_background(NULL); 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace message_center { 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NotificationView //////////////////////////////////////////////////////////// 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MessageView* NotificationView::Create(const Notification& notification, 356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MessageCenter* message_center, 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool expanded) { 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Use MessageSimpleView for simple notifications unless rich style 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // notifications are enabled. This preserves the appearance of notifications 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // created by existing code that uses webkitNotifications. 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!IsRichNotificationEnabled() && 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification.type() == NOTIFICATION_TYPE_SIMPLE) 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return new MessageSimpleView(notification, message_center); 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (notification.type()) { 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NOTIFICATION_TYPE_BASE_FORMAT: 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NOTIFICATION_TYPE_IMAGE: 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NOTIFICATION_TYPE_MULTIPLE: 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NOTIFICATION_TYPE_SIMPLE: 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the caller asks for an unrecognized kind of view (entirely possible 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // if an application is running on an older version of this code that 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // doesn't have the requested kind of notification template), we'll fall 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // back to a notification instance that will provide at least basic 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // functionality. 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(WARNING) << "Unable to fulfill request for unrecognized " 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "notification type " << notification.type() << ". " 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "Falling back to simple notification type."; 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Currently all roads lead to the generic NotificationView. 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return new NotificationView(notification, message_center, expanded); 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationView::NotificationView(const Notification& notification, 387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MessageCenter* message_center, 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool expanded) 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : MessageView(notification, message_center, expanded) { 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the opaque background that's above the view's shadow. 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) background_view_ = new views::View(); 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) background_view_->set_background(MakeBackground()); 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the top_view_, which collects into a vertical box all content 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // at the top of the notification (to the right of the icon) except for the 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // close button. 397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) top_view_ = new views::View(); 398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) top_view_->SetLayoutManager( 399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); 400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) top_view_->set_border(MakeEmptyBorder( 401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kTextTopPadding - 8, 0, kTextBottomPadding - 5, 0)); 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the title view if appropriate. 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_view_ = NULL; 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!notification.title().empty()) { 406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Font font = views::Label().font().DeriveFont(2); 407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int padding = kTitleLineHeight - font.GetHeight(); 408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title_view_ = new BoundedLabel( 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::TruncateString(notification.title(), kTitleCharacterLimit), font); 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title_view_->SetLineHeight(kTitleLineHeight); 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title_view_->SetLineLimit(kTitleLineLimit); 412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title_view_->SetColors(message_center::kRegularTextColor, 413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kRegularTextBackgroundColor); 414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) title_view_->set_border(MakeTextBorder(padding, 3, 0)); 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) top_view_->AddChildView(title_view_); 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the message view if appropriate. 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_view_ = NULL; 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!notification.message().empty()) { 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int padding = kMessageLineHeight - views::Label().font().GetHeight(); 422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_view_ = new BoundedLabel( 423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::TruncateString(notification.message(), kMessageCharacterLimit)); 424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_view_->SetLineHeight(kMessageLineHeight); 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_view_->SetVisible(!is_expanded() || !notification.items().size()); 426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_view_->SetColors(kDimTextColor, kDimTextBackgroundColor); 427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_view_->set_border(MakeTextBorder(padding, 4, 0)); 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) top_view_->AddChildView(message_view_); 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the list item views (up to a maximum). 432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int padding = kMessageLineHeight - views::Label().font().GetHeight(); 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<NotificationItem> items = notification.items(); 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) { 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ItemView* item_view = new ItemView(items[i]); 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) item_view->SetVisible(is_expanded()); 437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) item_view->set_border(MakeTextBorder(padding, i ? 0 : 4, 0)); 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) item_views_.push_back(item_view); 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) top_view_->AddChildView(item_view); 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the notification icon view. 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::ImageSkia icon = notification.icon().AsImageSkia(); 444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (notification.type() == NOTIFICATION_TYPE_SIMPLE && 445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (icon.width() != kIconSize || 446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) icon.height() != kIconSize || 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) HasAlpha(icon, GetWidget()))) { 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::ImageView* icon_view = new views::ImageView(); 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) icon_view->SetImage(icon); 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_view->SetImageSize(gfx::Size(kLegacyIconSize, kLegacyIconSize)); 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_view->SetHorizontalAlignment(views::ImageView::CENTER); 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_view->SetVerticalAlignment(views::ImageView::CENTER); 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_view->set_background(MakeBackground(kLegacyIconBackgroundColor)); 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_view_ = icon_view; 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) icon_view_ = new ProportionalImageView(icon); 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the bottom_view_, which collects into a vertical box all content 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // below the notification icon except for the expand button. 461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bottom_view_ = new views::View(); 462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bottom_view_->SetLayoutManager( 463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the image view if appropriate. 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) image_view_ = NULL; 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!notification.image().IsEmpty()) { 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) image_view_ = new ProportionalImageView(notification.image().AsImageSkia()); 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) image_view_->SetVisible(is_expanded()); 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bottom_view_->AddChildView(image_view_); 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create action buttons if appropriate. 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<ButtonInfo> buttons = notification.buttons(); 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < buttons.size(); ++i) { 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::View* separator = new views::ImageView(); 477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) separator->set_border(MakeSeparatorBorder(1, 0, kButtonSeparatorColor)); 4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bottom_view_->AddChildView(separator); 4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotificationButton* button = new NotificationButton(this); 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ButtonInfo button_info = buttons[i]; 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) button->SetTitle(button_info.title); 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) button->SetIcon(button_info.icon.AsImageSkia()); 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) action_buttons_.push_back(button); 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bottom_view_->AddChildView(button); 4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Put together the different content and control views. Layering those allows 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // for proper layout logic and it also allows the close and expand buttons to 4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // overlap the content as needed to provide large enough click and touch areas 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // (<http://crbug.com/168822> and <http://crbug.com/168856>). 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(background_view_); 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(top_view_); 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(icon_view_); 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(bottom_view_); 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(close_button()); 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(expand_button()); 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationView::~NotificationView() { 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size NotificationView::GetPreferredSize() { 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int top_width = top_view_->GetPreferredSize().width(); 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bottom_width = bottom_view_->GetPreferredSize().width(); 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int preferred_width = std::max(top_width, bottom_width) + GetInsets().width(); 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Size(preferred_width, GetHeightForWidth(preferred_width)); 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int NotificationView::GetHeightForWidth(int width) { 510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Get the height assuming no line limit changes. 511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int content_width = width - GetInsets().width(); 512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int top_height = top_view_->GetHeightForWidth(content_width); 513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int bottom_height = bottom_view_->GetHeightForWidth(content_width); 514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int content_height = std::max(top_height, kIconSize) + bottom_height; 515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // <http://crbug.com/230448> Fix: Adjust the height when the message_view's 517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // line limit would be different for the specified width than it currently is. 518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(dharcourt): Avoid BoxLayout and directly compute the correct height. 519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (message_view_) { 520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int used_limit = message_view_->GetLineLimit(); 521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int correct_limit = GetMessageLineLimit(width); 522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (used_limit != correct_limit) { 523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content_height -= GetMessageHeight(content_width, used_limit); 524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content_height += GetMessageHeight(content_width, correct_limit); 525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Adjust the height to make sure there is at least 16px of space below the 529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // icon if there is any space there (<http://crbug.com/232966>). 530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (content_height > kIconSize) 531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content_height = std::max(content_height, kIconSize + kIconBottomPadding); 532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return content_height + GetInsets().height(); 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationView::Layout() { 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Insets insets = GetInsets(); 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int content_width = width() - insets.width(); 5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int content_right = width() - insets.right(); 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Before any resizing, set or adjust the number of message lines. 542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (message_view_) 543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_view_->SetLineLimit(GetMessageLineLimit(width())); 544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Background. 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) background_view_->SetBounds(insets.left(), insets.top(), 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content_width, height() - insets.height()); 5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Top views. 5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int top_height = top_view_->GetHeightForWidth(content_width); 5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) top_view_->SetBounds(insets.left(), insets.top(), content_width, top_height); 5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Icon. 554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) icon_view_->SetBounds(insets.left(), insets.top(), kIconSize, kIconSize); 5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Bottom views. 557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int bottom_y = insets.top() + std::max(top_height, kIconSize); 5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bottom_height = bottom_view_->GetHeightForWidth(content_width); 5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bottom_view_->SetBounds(insets.left(), bottom_y, 5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content_width, bottom_height); 5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 562c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Close button. 5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size close_size(close_button()->GetPreferredSize()); 5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close_button()->SetBounds(content_right - close_size.width(), insets.top(), 5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close_size.width(), close_size.height()); 5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Expand button. 5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size expand_size(expand_button()->GetPreferredSize()); 5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int expand_y = bottom_y - expand_size.height(); 570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) expand_button()->SetVisible(IsExpansionNeeded(width())); 5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) expand_button()->SetBounds(content_right - expand_size.width(), expand_y, 5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) expand_size.width(), expand_size.height()); 5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NotificationView::ScrollRectToVisible(const gfx::Rect& rect) { 576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Notification want to show the whole notification when a part of it (like 577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // a button) gets focused. 578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View::ScrollRectToVisible(GetLocalBounds()); 579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 581a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)views::View* NotificationView::GetEventHandlerForPoint( 582a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const gfx::Point& point) { 583a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Want to return this for underlying views, otherwise GetCursor is not 584a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // called. But buttons are exceptions, they'll have their own event handlings. 585a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) std::vector<views::View*> buttons(action_buttons_); 586a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) buttons.push_back(close_button()); 587a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) buttons.push_back(expand_button()); 588a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 589a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) for (size_t i = 0; i < buttons.size(); ++i) { 590a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) gfx::Point point_in_child = point; 591a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ConvertPointToTarget(this, buttons[i], &point_in_child); 592a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (buttons[i]->HitTestPoint(point_in_child)) 593a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return buttons[i]->GetEventHandlerForPoint(point_in_child); 594a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 595a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 596a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return this; 597a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 598a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 599a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)gfx::NativeCursor NotificationView::GetCursor(const ui::MouseEvent& event) { 600a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#if defined(USE_AURA) 601a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return ui::kCursorHand; 602a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#elif defined(OS_WIN) 603a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_HAND); 604a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return g_hand_cursor; 605a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 606a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 607a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationView::ButtonPressed(views::Button* sender, 6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::Event& event) { 6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // See if the button pressed was an action button. 6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < action_buttons_.size(); ++i) { 6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (sender == action_buttons_[i]) { 613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center()->ClickOnNotificationButton(notification_id(), i); 6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Let the superclass handled anything other than action buttons. 6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MessageView::ButtonPressed(sender, event); 6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 621c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Adjust notification subviews for expansion. 6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (sender == expand_button()) { 6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (message_view_ && item_views_.size()) 6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_view_->SetVisible(false); 6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < item_views_.size(); ++i) 6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) item_views_[i]->SetVisible(true); 6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (image_view_) 6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) image_view_->SetVisible(true); 6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) expand_button()->SetVisible(false); 6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PreferredSizeChanged(); 6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaint(); 6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool NotificationView::IsExpansionNeeded(int width) { 636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return (!is_expanded() && 637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (image_view_ || 638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) item_views_.size() || 639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) IsMessageExpansionNeeded(width))); 640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool NotificationView::IsMessageExpansionNeeded(int width) { 643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int current = GetMessageLines(width, GetMessageLineLimit(width)); 644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int expanded = GetMessageLines(width, kMessageExpandedLineLimit); 645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return current < expanded; 646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int NotificationView::GetMessageLineLimit(int width) { 649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Expanded notifications get a larger limit, except for image notifications, 650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // whose images must be kept flush against their icons. 651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (is_expanded() && !image_view_) 652c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return kMessageExpandedLineLimit; 653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If there's a title ensure title + message lines <= collapsed line limit. 655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (title_view_) { 656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int title_lines = title_view_->GetLinesForWidthAndLimit(width, -1); 657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::max(kMessageCollapsedLineLimit - title_lines, 0); 658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return kMessageCollapsedLineLimit; 661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int NotificationView::GetMessageLines(int width, int limit) { 664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return message_view_ ? 665c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_view_->GetLinesForWidthAndLimit(width, limit) : 0; 666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int NotificationView::GetMessageHeight(int width, int limit) { 669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return message_view_ ? 670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_view_->GetSizeForWidthAndLines(width, limit).height() : 0; 6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace message_center 674