- add sources.
[platform/framework/web/crosswalk.git] / src / ash / popup_message.cc
1 // Copyright (c) 2013 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 "ash/popup_message.h"
6
7 #include "ash/wm/window_animations.h"
8 #include "grit/ash_resources.h"
9 #include "ui/base/resource/resource_bundle.h"
10 #include "ui/gfx/insets.h"
11 #include "ui/views/bubble/bubble_delegate.h"
12 #include "ui/views/bubble/bubble_frame_view.h"
13 #include "ui/views/controls/image_view.h"
14 #include "ui/views/controls/label.h"
15 #include "ui/views/layout/box_layout.h"
16 #include "ui/views/widget/widget.h"
17
18 namespace ash {
19 namespace {
20 const int kMessageTopBottomMargin = 10;
21 const int kMessageLeftRightMargin = 10;
22 const int kMessageMinHeight = 29 - 2 * kMessageTopBottomMargin;
23 const SkColor kMessageTextColor = SkColorSetRGB(0x22, 0x22, 0x22);
24
25 // The maximum width of the Message bubble.  Borrowed the value from
26 // ash/message/message_controller.cc
27 const int kMessageMaxWidth = 250;
28
29 // The offset for the Message bubble - making sure that the bubble is flush
30 // with the shelf. The offset includes the arrow size in pixels as well as
31 // the activation bar and other spacing elements.
32 const int kArrowOffsetLeftRight = 11;
33 const int kArrowOffsetTopBottom = 7;
34
35 // The number of pixels between the icon and the text.
36 const int kHorizontalPopupPaddingBetweenItems = 10;
37
38 // The number of pixels between the text items.
39 const int kVerticalPopupPaddingBetweenItems = 10;
40 }  // namespace
41
42 // The implementation of Message of the launcher.
43 class PopupMessage::MessageBubble : public views::BubbleDelegateView {
44  public:
45   MessageBubble(const base::string16& caption,
46                 const base::string16& message,
47                 IconType message_type,
48                 views::View* anchor,
49                 views::BubbleBorder::Arrow arrow_orientation,
50                 const gfx::Size& size_override,
51                 int arrow_offset);
52
53   void Close();
54
55  private:
56   // views::View overrides:
57   virtual gfx::Size GetPreferredSize() OVERRIDE;
58
59   // Each component (width/height) can force a size override for that component
60   // if not 0.
61   gfx::Size size_override_;
62
63   DISALLOW_COPY_AND_ASSIGN(MessageBubble);
64 };
65
66 PopupMessage::MessageBubble::MessageBubble(const base::string16& caption,
67                                            const base::string16& message,
68                                            IconType message_type,
69                                            views::View* anchor,
70                                            views::BubbleBorder::Arrow arrow,
71                                            const gfx::Size& size_override,
72                                            int arrow_offset)
73     : views::BubbleDelegateView(anchor, arrow),
74       size_override_(size_override) {
75   gfx::Insets insets = gfx::Insets(kArrowOffsetTopBottom,
76                                    kArrowOffsetLeftRight,
77                                    kArrowOffsetTopBottom,
78                                    kArrowOffsetLeftRight);
79   // An anchor can have an asymmetrical border for spacing reasons. Adjust the
80   // anchor location for this.
81   if (anchor->border())
82     insets += anchor->border()->GetInsets();
83
84   set_anchor_view_insets(insets);
85   set_close_on_esc(false);
86   set_close_on_deactivate(false);
87   set_use_focusless(true);
88   set_accept_events(false);
89
90   set_margins(gfx::Insets(kMessageTopBottomMargin, kMessageLeftRightMargin,
91                           kMessageTopBottomMargin, kMessageLeftRightMargin));
92   set_shadow(views::BubbleBorder::SMALL_SHADOW);
93
94   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
95   SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
96                                         kHorizontalPopupPaddingBetweenItems));
97
98   // Here is the layout:
99   //         arrow_offset (if not 0)
100   //       |-------------|
101   //       |             ^
102   //       +-------------------------------------------------+
103   //      -|                                                 |-
104   //  icon |  [!]  Caption in bold which can be multi line   | caption_label
105   //      -|                                                 |-
106   //       |       Message text which can be multi line      | message_label
107   //       |       as well.                                  |
108   //       |                                                 |-
109   //       +-------------------------------------------------+
110   //             |------------details container--------------|
111   // Note that the icon, caption and massage are optional.
112
113   // Add the icon to the first column (if there is one).
114   if (message_type != ICON_NONE) {
115     views::ImageView* icon = new views::ImageView();
116     icon->SetImage(
117         bundle.GetImageNamed(IDR_AURA_WARNING_ICON).ToImageSkia());
118     icon->SetVerticalAlignment(views::ImageView::LEADING);
119     AddChildView(icon);
120   }
121
122   // Create a container for the text items and use it as second column.
123   views::View* details = new views::View();
124   AddChildView(details);
125   details->SetLayoutManager(new views::BoxLayout(
126       views::BoxLayout::kVertical, 0, 0, kVerticalPopupPaddingBetweenItems));
127
128   // The caption label.
129   if (!caption.empty()) {
130     views::Label* caption_label = new views::Label(caption);
131     caption_label->SetMultiLine(true);
132     caption_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
133     caption_label->SetFont(bundle.GetFont(ui::ResourceBundle::BoldFont));
134     caption_label->SetEnabledColor(kMessageTextColor);
135     details->AddChildView(caption_label);
136   }
137
138   // The message label.
139   if (!message.empty()) {
140     views::Label* message_label = new views::Label(message);
141     message_label->SetMultiLine(true);
142     message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
143     message_label->SetEnabledColor(kMessageTextColor);
144     details->AddChildView(message_label);
145   }
146   views::BubbleDelegateView::CreateBubble(this);
147
148   // Change the arrow offset if needed.
149   if (arrow_offset) {
150     // With the creation of the bubble, the bubble got already placed (and
151     // possibly re-oriented to fit on the screen). Since it is not possible to
152     // set the arrow offset before the creation, we need to set the offset,
153     // and the orientation variables again and force a re-placement.
154     GetBubbleFrameView()->bubble_border()->set_arrow_offset(arrow_offset);
155     GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
156     SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR);
157   }
158 }
159
160 void PopupMessage::MessageBubble::Close() {
161   if (GetWidget())
162     GetWidget()->Close();
163 }
164
165 gfx::Size PopupMessage::MessageBubble::GetPreferredSize() {
166   gfx::Size pref_size = views::BubbleDelegateView::GetPreferredSize();
167   // Override the size with either the provided size or adjust it to not
168   // violate our minimum / maximum sizes.
169   if (size_override_.height())
170     pref_size.set_height(size_override_.height());
171   else if (pref_size.height() < kMessageMinHeight)
172     pref_size.set_height(kMessageMinHeight);
173
174   if (size_override_.width())
175     pref_size.set_width(size_override_.width());
176   else if (pref_size.width() > kMessageMaxWidth)
177     pref_size.set_width(kMessageMaxWidth);
178
179   return pref_size;
180 }
181
182 PopupMessage::PopupMessage(const base::string16& caption,
183                            const base::string16& message,
184                            IconType message_type,
185                            views::View* anchor,
186                            views::BubbleBorder::Arrow arrow,
187                            const gfx::Size& size_override,
188                            int arrow_offset)
189     : view_(NULL) {
190   view_ = new MessageBubble(
191       caption, message, message_type, anchor, arrow, size_override,
192       arrow_offset);
193   widget_ = view_->GetWidget();
194
195   gfx::NativeView native_view = widget_->GetNativeView();
196   views::corewm::SetWindowVisibilityAnimationType(
197       native_view, views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
198   views::corewm::SetWindowVisibilityAnimationTransition(
199       native_view, views::corewm::ANIMATE_HIDE);
200   view_->GetWidget()->Show();
201 }
202
203 PopupMessage::~PopupMessage() {
204   CancelHidingAnimation();
205   Close();
206 }
207
208 void PopupMessage::Close() {
209   if (view_) {
210     view_->Close();
211     view_ = NULL;
212     widget_ = NULL;
213   }
214 }
215
216 void PopupMessage::CancelHidingAnimation() {
217   if (!widget_ || !widget_->GetNativeView())
218     return;
219
220   gfx::NativeView native_view = widget_->GetNativeView();
221   views::corewm::SetWindowVisibilityAnimationTransition(
222       native_view, views::corewm::ANIMATE_NONE);
223 }
224
225 }  // namespace ash