Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / message_center / views / message_view.cc
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.
4
5 #include "ui/message_center/views/message_view.h"
6
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/message_center/message_center.h"
15 #include "ui/message_center/message_center_style.h"
16 #include "ui/message_center/views/padded_button.h"
17 #include "ui/resources/grit/ui_resources.h"
18 #include "ui/strings/grit/ui_strings.h"
19 #include "ui/views/background.h"
20 #include "ui/views/controls/button/image_button.h"
21 #include "ui/views/controls/image_view.h"
22 #include "ui/views/controls/scroll_view.h"
23 #include "ui/views/focus/focus_manager.h"
24 #include "ui/views/painter.h"
25 #include "ui/views/shadow_border.h"
26
27 namespace {
28
29 const int kCloseIconTopPadding = 5;
30 const int kCloseIconRightPadding = 5;
31
32 const int kShadowOffset = 1;
33 const int kShadowBlur = 4;
34
35 const gfx::ImageSkia CreateImage(int width, int height, SkColor color) {
36   SkBitmap bitmap;
37   bitmap.allocN32Pixels(width, height);
38   bitmap.eraseColor(color);
39   return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
40 }
41
42 // Take the alpha channel of small_image, mask it with the foreground,
43 // then add the masked foreground on top of the background
44 const gfx::ImageSkia GetMaskedSmallImage(const gfx::ImageSkia& small_image) {
45   int width = small_image.width();
46   int height = small_image.height();
47
48   // Background color grey
49   const gfx::ImageSkia background = CreateImage(
50       width, height, message_center::kSmallImageMaskBackgroundColor);
51   // Foreground color white
52   const gfx::ImageSkia foreground = CreateImage(
53       width, height, message_center::kSmallImageMaskForegroundColor);
54   const gfx::ImageSkia masked_small_image =
55       gfx::ImageSkiaOperations::CreateMaskedImage(foreground, small_image);
56   return gfx::ImageSkiaOperations::CreateSuperimposedImage(background,
57                                                            masked_small_image);
58 }
59
60 }  // namespace
61
62 namespace message_center {
63
64 MessageView::MessageView(MessageViewController* controller,
65                          const std::string& notification_id,
66                          const NotifierId& notifier_id,
67                          const gfx::ImageSkia& small_image,
68                          const base::string16& display_source)
69     : controller_(controller),
70       notification_id_(notification_id),
71       notifier_id_(notifier_id),
72       background_view_(NULL),
73       scroller_(NULL),
74       display_source_(display_source) {
75   SetFocusable(true);
76
77   // Create the opaque background that's above the view's shadow.
78   background_view_ = new views::View();
79   background_view_->set_background(
80       views::Background::CreateSolidBackground(kNotificationBackgroundColor));
81   AddChildView(background_view_);
82
83   const gfx::ImageSkia masked_small_image = GetMaskedSmallImage(small_image);
84   views::ImageView* small_image_view = new views::ImageView();
85   small_image_view->SetImage(masked_small_image);
86   small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize));
87   // The small image view should be added to view hierarchy by the derived
88   // class. This ensures that it is on top of other views.
89   small_image_view->set_owned_by_client();
90   small_image_view_.reset(small_image_view);
91
92   PaddedButton *close = new PaddedButton(this);
93   close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding);
94   close->SetNormalImage(IDR_NOTIFICATION_CLOSE);
95   close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER);
96   close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED);
97   close->set_animate_on_state_change(false);
98   close->SetAccessibleName(l10n_util::GetStringUTF16(
99       IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
100   // The close button should be added to view hierarchy by the derived class.
101   // This ensures that it is on top of other views.
102   close->set_owned_by_client();
103   close_button_.reset(close);
104
105   focus_painter_ = views::Painter::CreateSolidFocusPainter(
106       kFocusBorderColor,
107       gfx::Insets(0, 1, 3, 2)).Pass();
108 }
109
110 MessageView::~MessageView() {
111 }
112
113 void MessageView::UpdateWithNotification(const Notification& notification) {
114   const gfx::ImageSkia masked_small_image =
115       GetMaskedSmallImage(notification.small_image().AsImageSkia());
116   small_image_view_->SetImage(masked_small_image);
117   display_source_ = notification.display_source();
118 }
119
120 // static
121 gfx::Insets MessageView::GetShadowInsets() {
122   return gfx::Insets(kShadowBlur / 2 - kShadowOffset,
123                      kShadowBlur / 2,
124                      kShadowBlur / 2 + kShadowOffset,
125                      kShadowBlur / 2);
126 }
127
128 void MessageView::CreateShadowBorder() {
129   SetBorder(scoped_ptr<views::Border>(
130       new views::ShadowBorder(kShadowBlur,
131                               message_center::kShadowColor,
132                               kShadowOffset,  // Vertical offset.
133                               0)));           // Horizontal offset.
134 }
135
136 bool MessageView::IsCloseButtonFocused() {
137   views::FocusManager* focus_manager = GetFocusManager();
138   return focus_manager && focus_manager->GetFocusedView() == close_button();
139 }
140
141 void MessageView::RequestFocusOnCloseButton() {
142   close_button_->RequestFocus();
143 }
144
145 void MessageView::GetAccessibleState(ui::AXViewState* state) {
146   state->role = ui::AX_ROLE_BUTTON;
147   state->name = accessible_name_;
148 }
149
150 bool MessageView::OnMousePressed(const ui::MouseEvent& event) {
151   if (!event.IsOnlyLeftMouseButton())
152     return false;
153
154   controller_->ClickOnNotification(notification_id_);
155   return true;
156 }
157
158 bool MessageView::OnKeyPressed(const ui::KeyEvent& event) {
159   if (event.flags() != ui::EF_NONE)
160     return false;
161
162   if (event.key_code() == ui::VKEY_RETURN) {
163     controller_->ClickOnNotification(notification_id_);
164     return true;
165   } else if ((event.key_code() == ui::VKEY_DELETE ||
166               event.key_code() == ui::VKEY_BACK)) {
167     controller_->RemoveNotification(notification_id_, true);  // By user.
168     return true;
169   }
170
171   return false;
172 }
173
174 bool MessageView::OnKeyReleased(const ui::KeyEvent& event) {
175   // Space key handling is triggerred at key-release timing. See
176   // ui/views/controls/buttons/custom_button.cc for why.
177   if (event.flags() != ui::EF_NONE || event.flags() != ui::VKEY_SPACE)
178     return false;
179
180   controller_->ClickOnNotification(notification_id_);
181   return true;
182 }
183
184 void MessageView::OnPaint(gfx::Canvas* canvas) {
185   DCHECK_EQ(this, close_button_->parent());
186   DCHECK_EQ(this, small_image_view_->parent());
187   SlideOutView::OnPaint(canvas);
188   views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
189 }
190
191 void MessageView::OnFocus() {
192   SlideOutView::OnFocus();
193   // We paint a focus indicator.
194   SchedulePaint();
195 }
196
197 void MessageView::OnBlur() {
198   SlideOutView::OnBlur();
199   // We paint a focus indicator.
200   SchedulePaint();
201 }
202
203 void MessageView::Layout() {
204   gfx::Rect content_bounds = GetContentsBounds();
205
206   // Background.
207   background_view_->SetBoundsRect(content_bounds);
208
209   // Close button.
210   gfx::Size close_size(close_button_->GetPreferredSize());
211   gfx::Rect close_rect(content_bounds.right() - close_size.width(),
212                        content_bounds.y(),
213                        close_size.width(),
214                        close_size.height());
215   close_button_->SetBoundsRect(close_rect);
216
217   gfx::Size small_image_size(small_image_view_->GetPreferredSize());
218   gfx::Rect small_image_rect(small_image_size);
219   small_image_rect.set_origin(gfx::Point(
220       content_bounds.right() - small_image_size.width() - kSmallImagePadding,
221       content_bounds.bottom() - small_image_size.height() -
222           kSmallImagePadding));
223   small_image_view_->SetBoundsRect(small_image_rect);
224 }
225
226 void MessageView::OnGestureEvent(ui::GestureEvent* event) {
227   switch (event->type()) {
228     case ui::ET_GESTURE_TAP_DOWN: {
229       SetDrawBackgroundAsActive(true);
230       break;
231     }
232     case ui::ET_GESTURE_TAP_CANCEL:
233     case ui::ET_GESTURE_END: {
234       SetDrawBackgroundAsActive(false);
235       break;
236     }
237     case ui::ET_GESTURE_TAP: {
238       SetDrawBackgroundAsActive(false);
239       controller_->ClickOnNotification(notification_id_);
240       event->SetHandled();
241       return;
242     }
243     default: {
244       // Do nothing
245     }
246   }
247
248   SlideOutView::OnGestureEvent(event);
249   // Do not return here by checking handled(). SlideOutView calls SetHandled()
250   // even though the scroll gesture doesn't make no (or little) effects on the
251   // slide-out behavior. See http://crbug.com/172991
252
253   if (!event->IsScrollGestureEvent() && !event->IsFlingScrollEvent())
254     return;
255
256   if (scroller_)
257     scroller_->OnGestureEvent(event);
258   event->SetHandled();
259 }
260
261 void MessageView::ButtonPressed(views::Button* sender,
262                                 const ui::Event& event) {
263   if (sender == close_button()) {
264     controller_->RemoveNotification(notification_id_, true);  // By user.
265   }
266 }
267
268 void MessageView::OnSlideOut() {
269   controller_->RemoveNotification(notification_id_, true);  // By user.
270 }
271
272 void MessageView::SetDrawBackgroundAsActive(bool active) {
273   if (!switches::IsTouchFeedbackEnabled())
274     return;
275   background_view_->background()->
276       SetNativeControlColor(active ? kHoveredButtonBackgroundColor :
277                                      kNotificationBackgroundColor);
278   SchedulePaint();
279 }
280
281 }  // namespace message_center