Re-land: C++ readability review
[chromium-blink-merge.git] / ui / message_center / views / message_view.cc
blobef527a6de4079a6233dd2ee6e220ddd626d79ee9
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/message_center/views/message_view.h"
7 #include "ui/accessibility/ax_view_state.h"
8 #include "ui/base/l10n/l10n_util.h"
9 #include "ui/base/models/simple_menu_model.h"
10 #include "ui/base/ui_base_switches_util.h"
11 #include "ui/compositor/scoped_layer_animation_settings.h"
12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/image/image_skia_operations.h"
14 #include "ui/gfx/shadow_value.h"
15 #include "ui/message_center/message_center.h"
16 #include "ui/message_center/message_center_style.h"
17 #include "ui/message_center/views/padded_button.h"
18 #include "ui/resources/grit/ui_resources.h"
19 #include "ui/strings/grit/ui_strings.h"
20 #include "ui/views/background.h"
21 #include "ui/views/controls/button/image_button.h"
22 #include "ui/views/controls/image_view.h"
23 #include "ui/views/controls/scroll_view.h"
24 #include "ui/views/focus/focus_manager.h"
25 #include "ui/views/painter.h"
26 #include "ui/views/shadow_border.h"
28 namespace {
30 const int kCloseIconTopPadding = 5;
31 const int kCloseIconRightPadding = 5;
33 const int kShadowOffset = 1;
34 const int kShadowBlur = 4;
36 const gfx::ImageSkia CreateImage(int width, int height, SkColor color) {
37 SkBitmap bitmap;
38 bitmap.allocN32Pixels(width, height);
39 bitmap.eraseColor(color);
40 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
43 // Take the alpha channel of small_image, mask it with the foreground,
44 // then add the masked foreground on top of the background
45 const gfx::ImageSkia GetMaskedSmallImage(const gfx::ImageSkia& small_image) {
46 int width = small_image.width();
47 int height = small_image.height();
49 // Background color grey
50 const gfx::ImageSkia background = CreateImage(
51 width, height, message_center::kSmallImageMaskBackgroundColor);
52 // Foreground color white
53 const gfx::ImageSkia foreground = CreateImage(
54 width, height, message_center::kSmallImageMaskForegroundColor);
55 const gfx::ImageSkia masked_small_image =
56 gfx::ImageSkiaOperations::CreateMaskedImage(foreground, small_image);
57 return gfx::ImageSkiaOperations::CreateSuperimposedImage(background,
58 masked_small_image);
61 } // namespace
63 namespace message_center {
65 MessageView::MessageView(MessageViewController* controller,
66 const std::string& notification_id,
67 const NotifierId& notifier_id,
68 const gfx::ImageSkia& small_image,
69 const base::string16& display_source)
70 : controller_(controller),
71 notification_id_(notification_id),
72 notifier_id_(notifier_id),
73 background_view_(NULL),
74 scroller_(NULL),
75 display_source_(display_source) {
76 SetFocusable(true);
78 // Create the opaque background that's above the view's shadow.
79 background_view_ = new views::View();
80 background_view_->set_background(
81 views::Background::CreateSolidBackground(kNotificationBackgroundColor));
82 AddChildView(background_view_);
84 const gfx::ImageSkia masked_small_image = GetMaskedSmallImage(small_image);
85 views::ImageView* small_image_view = new views::ImageView();
86 small_image_view->SetImage(masked_small_image);
87 small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize));
88 // The small image view should be added to view hierarchy by the derived
89 // class. This ensures that it is on top of other views.
90 small_image_view->set_owned_by_client();
91 small_image_view_.reset(small_image_view);
93 PaddedButton *close = new PaddedButton(this);
94 close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding);
95 close->SetNormalImage(IDR_NOTIFICATION_CLOSE);
96 close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER);
97 close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED);
98 close->set_animate_on_state_change(false);
99 close->SetAccessibleName(l10n_util::GetStringUTF16(
100 IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
101 // The close button should be added to view hierarchy by the derived class.
102 // This ensures that it is on top of other views.
103 close->set_owned_by_client();
104 close_button_.reset(close);
106 focus_painter_ = views::Painter::CreateSolidFocusPainter(
107 kFocusBorderColor,
108 gfx::Insets(0, 1, 3, 2)).Pass();
111 MessageView::~MessageView() {
114 void MessageView::UpdateWithNotification(const Notification& notification) {
115 const gfx::ImageSkia masked_small_image =
116 GetMaskedSmallImage(notification.small_image().AsImageSkia());
117 small_image_view_->SetImage(masked_small_image);
118 display_source_ = notification.display_source();
121 // static
122 gfx::Insets MessageView::GetShadowInsets() {
123 return gfx::Insets(kShadowBlur / 2 - kShadowOffset,
124 kShadowBlur / 2,
125 kShadowBlur / 2 + kShadowOffset,
126 kShadowBlur / 2);
129 void MessageView::CreateShadowBorder() {
130 SetBorder(scoped_ptr<views::Border>(new views::ShadowBorder(
131 gfx::ShadowValue(gfx::Vector2d(0, kShadowOffset), kShadowBlur,
132 message_center::kShadowColor))));
135 bool MessageView::IsCloseButtonFocused() {
136 views::FocusManager* focus_manager = GetFocusManager();
137 return focus_manager && focus_manager->GetFocusedView() == close_button();
140 void MessageView::RequestFocusOnCloseButton() {
141 close_button_->RequestFocus();
144 void MessageView::GetAccessibleState(ui::AXViewState* state) {
145 state->role = ui::AX_ROLE_BUTTON;
146 state->name = accessible_name_;
149 bool MessageView::OnMousePressed(const ui::MouseEvent& event) {
150 if (!event.IsOnlyLeftMouseButton())
151 return false;
153 controller_->ClickOnNotification(notification_id_);
154 return true;
157 bool MessageView::OnKeyPressed(const ui::KeyEvent& event) {
158 if (event.flags() != ui::EF_NONE)
159 return false;
161 if (event.key_code() == ui::VKEY_RETURN) {
162 controller_->ClickOnNotification(notification_id_);
163 return true;
164 } else if ((event.key_code() == ui::VKEY_DELETE ||
165 event.key_code() == ui::VKEY_BACK)) {
166 controller_->RemoveNotification(notification_id_, true); // By user.
167 return true;
170 return false;
173 bool MessageView::OnKeyReleased(const ui::KeyEvent& event) {
174 // Space key handling is triggerred at key-release timing. See
175 // ui/views/controls/buttons/custom_button.cc for why.
176 if (event.flags() != ui::EF_NONE || event.flags() != ui::VKEY_SPACE)
177 return false;
179 controller_->ClickOnNotification(notification_id_);
180 return true;
183 void MessageView::OnPaint(gfx::Canvas* canvas) {
184 DCHECK_EQ(this, close_button_->parent());
185 DCHECK_EQ(this, small_image_view_->parent());
186 SlideOutView::OnPaint(canvas);
187 views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
190 void MessageView::OnFocus() {
191 SlideOutView::OnFocus();
192 // We paint a focus indicator.
193 SchedulePaint();
196 void MessageView::OnBlur() {
197 SlideOutView::OnBlur();
198 // We paint a focus indicator.
199 SchedulePaint();
202 void MessageView::Layout() {
203 gfx::Rect content_bounds = GetContentsBounds();
205 // Background.
206 background_view_->SetBoundsRect(content_bounds);
208 // Close button.
209 gfx::Size close_size(close_button_->GetPreferredSize());
210 gfx::Rect close_rect(content_bounds.right() - close_size.width(),
211 content_bounds.y(),
212 close_size.width(),
213 close_size.height());
214 close_button_->SetBoundsRect(close_rect);
216 gfx::Size small_image_size(small_image_view_->GetPreferredSize());
217 gfx::Rect small_image_rect(small_image_size);
218 small_image_rect.set_origin(gfx::Point(
219 content_bounds.right() - small_image_size.width() - kSmallImagePadding,
220 content_bounds.bottom() - small_image_size.height() -
221 kSmallImagePadding));
222 small_image_view_->SetBoundsRect(small_image_rect);
225 void MessageView::OnGestureEvent(ui::GestureEvent* event) {
226 switch (event->type()) {
227 case ui::ET_GESTURE_TAP_DOWN: {
228 SetDrawBackgroundAsActive(true);
229 break;
231 case ui::ET_GESTURE_TAP_CANCEL:
232 case ui::ET_GESTURE_END: {
233 SetDrawBackgroundAsActive(false);
234 break;
236 case ui::ET_GESTURE_TAP: {
237 SetDrawBackgroundAsActive(false);
238 controller_->ClickOnNotification(notification_id_);
239 event->SetHandled();
240 return;
242 default: {
243 // Do nothing
247 SlideOutView::OnGestureEvent(event);
248 // Do not return here by checking handled(). SlideOutView calls SetHandled()
249 // even though the scroll gesture doesn't make no (or little) effects on the
250 // slide-out behavior. See http://crbug.com/172991
252 if (!event->IsScrollGestureEvent() && !event->IsFlingScrollEvent())
253 return;
255 if (scroller_)
256 scroller_->OnGestureEvent(event);
257 event->SetHandled();
260 void MessageView::ButtonPressed(views::Button* sender,
261 const ui::Event& event) {
262 if (sender == close_button()) {
263 controller_->RemoveNotification(notification_id_, true); // By user.
267 void MessageView::OnSlideOut() {
268 controller_->RemoveNotification(notification_id_, true); // By user.
271 void MessageView::SetDrawBackgroundAsActive(bool active) {
272 if (!switches::IsTouchFeedbackEnabled())
273 return;
274 background_view_->background()->
275 SetNativeControlColor(active ? kHoveredButtonBackgroundColor :
276 kNotificationBackgroundColor);
277 SchedulePaint();
280 } // namespace message_center