| OLD | NEW |
| (Empty) |
| 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/geometry/insets.h" | |
| 11 #include "ui/views/bubble/bubble_dialog_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::BubbleDialogDelegateView { | |
| 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 ClosePopup(); | |
| 54 | |
| 55 private: | |
| 56 // views::BubbleDialogDelegateView overrides: | |
| 57 gfx::Size GetPreferredSize() const override; | |
| 58 int GetDialogButtons() const override; | |
| 59 | |
| 60 // Each component (width/height) can force a size override for that component | |
| 61 // if not 0. | |
| 62 gfx::Size size_override_; | |
| 63 | |
| 64 DISALLOW_COPY_AND_ASSIGN(MessageBubble); | |
| 65 }; | |
| 66 | |
| 67 // static | |
| 68 const int PopupMessage::kCaptionLabelID = 1000; | |
| 69 const int PopupMessage::kMessageLabelID = 1001; | |
| 70 | |
| 71 PopupMessage::MessageBubble::MessageBubble(const base::string16& caption, | |
| 72 const base::string16& message, | |
| 73 IconType message_type, | |
| 74 views::View* anchor, | |
| 75 views::BubbleBorder::Arrow arrow, | |
| 76 const gfx::Size& size_override, | |
| 77 int arrow_offset) | |
| 78 : views::BubbleDialogDelegateView(anchor, arrow), | |
| 79 size_override_(size_override) { | |
| 80 gfx::Insets insets = | |
| 81 gfx::Insets(kArrowOffsetTopBottom, kArrowOffsetLeftRight, | |
| 82 kArrowOffsetTopBottom, kArrowOffsetLeftRight); | |
| 83 // An anchor can have an asymmetrical border for spacing reasons. Adjust the | |
| 84 // anchor location for this. | |
| 85 if (anchor->border()) | |
| 86 insets += anchor->border()->GetInsets(); | |
| 87 | |
| 88 set_anchor_view_insets(insets); | |
| 89 set_close_on_deactivate(false); | |
| 90 set_can_activate(false); | |
| 91 set_accept_events(false); | |
| 92 | |
| 93 set_margins(gfx::Insets(kMessageTopBottomMargin, kMessageLeftRightMargin, | |
| 94 kMessageTopBottomMargin, kMessageLeftRightMargin)); | |
| 95 set_shadow(views::BubbleBorder::SMALL_SHADOW); | |
| 96 | |
| 97 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
| 98 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, | |
| 99 kHorizontalPopupPaddingBetweenItems)); | |
| 100 | |
| 101 // Here is the layout: | |
| 102 // arrow_offset (if not 0) | |
| 103 // |-------------| | |
| 104 // | ^ | |
| 105 // +-------------------------------------------------+ | |
| 106 // -| |- | |
| 107 // icon | [!] Caption in bold which can be multi line | caption_label | |
| 108 // -| |- | |
| 109 // | Message text which can be multi line | message_label | |
| 110 // | as well. | | |
| 111 // | |- | |
| 112 // +-------------------------------------------------+ | |
| 113 // |------------details container--------------| | |
| 114 // Note that the icon, caption and message are optional. | |
| 115 | |
| 116 // Add the icon to the first column (if there is one). | |
| 117 if (message_type != ICON_NONE) { | |
| 118 views::ImageView* icon = new views::ImageView(); | |
| 119 icon->SetImage(bundle.GetImageNamed(IDR_AURA_WARNING_ICON).ToImageSkia()); | |
| 120 icon->SetVerticalAlignment(views::ImageView::LEADING); | |
| 121 AddChildView(icon); | |
| 122 } | |
| 123 | |
| 124 // Create a container for the text items and use it as second column. | |
| 125 views::View* details = new views::View(); | |
| 126 AddChildView(details); | |
| 127 details->SetLayoutManager(new views::BoxLayout( | |
| 128 views::BoxLayout::kVertical, 0, 0, kVerticalPopupPaddingBetweenItems)); | |
| 129 | |
| 130 // The caption label. | |
| 131 if (!caption.empty()) { | |
| 132 views::Label* caption_label = new views::Label(caption); | |
| 133 caption_label->set_id(kCaptionLabelID); | |
| 134 caption_label->SetMultiLine(true); | |
| 135 caption_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 136 caption_label->SetFontList( | |
| 137 bundle.GetFontList(ui::ResourceBundle::BoldFont)); | |
| 138 caption_label->SetEnabledColor(kMessageTextColor); | |
| 139 details->AddChildView(caption_label); | |
| 140 } | |
| 141 | |
| 142 // The message label. | |
| 143 if (!message.empty()) { | |
| 144 views::Label* message_label = new views::Label(message); | |
| 145 message_label->set_id(kMessageLabelID); | |
| 146 message_label->SetMultiLine(true); | |
| 147 message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 148 message_label->SetEnabledColor(kMessageTextColor); | |
| 149 details->AddChildView(message_label); | |
| 150 } | |
| 151 views::BubbleDialogDelegateView::CreateBubble(this); | |
| 152 | |
| 153 // Change the arrow offset if needed. | |
| 154 if (arrow_offset) { | |
| 155 // With the creation of the bubble, the bubble got already placed (and | |
| 156 // possibly re-oriented to fit on the screen). Since it is not possible to | |
| 157 // set the arrow offset before the creation, we need to set the offset, | |
| 158 // and the orientation variables again and force a re-placement. | |
| 159 GetBubbleFrameView()->bubble_border()->set_arrow_offset(arrow_offset); | |
| 160 GetBubbleFrameView()->bubble_border()->set_arrow(arrow); | |
| 161 SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void PopupMessage::MessageBubble::ClosePopup() { | |
| 166 if (GetWidget()) | |
| 167 GetWidget()->Close(); | |
| 168 } | |
| 169 | |
| 170 gfx::Size PopupMessage::MessageBubble::GetPreferredSize() const { | |
| 171 gfx::Size pref_size = views::BubbleDialogDelegateView::GetPreferredSize(); | |
| 172 // Override the size with either the provided size or adjust it to not | |
| 173 // violate our minimum / maximum sizes. | |
| 174 if (size_override_.height()) | |
| 175 pref_size.set_height(size_override_.height()); | |
| 176 else if (pref_size.height() < kMessageMinHeight) | |
| 177 pref_size.set_height(kMessageMinHeight); | |
| 178 | |
| 179 if (size_override_.width()) | |
| 180 pref_size.set_width(size_override_.width()); | |
| 181 else if (pref_size.width() > kMessageMaxWidth) | |
| 182 pref_size.set_width(kMessageMaxWidth); | |
| 183 | |
| 184 return pref_size; | |
| 185 } | |
| 186 | |
| 187 int PopupMessage::MessageBubble::GetDialogButtons() const { | |
| 188 return ui::DIALOG_BUTTON_NONE; | |
| 189 } | |
| 190 | |
| 191 PopupMessage::PopupMessage(const base::string16& caption, | |
| 192 const base::string16& message, | |
| 193 IconType message_type, | |
| 194 views::View* anchor, | |
| 195 views::BubbleBorder::Arrow arrow, | |
| 196 const gfx::Size& size_override, | |
| 197 int arrow_offset) | |
| 198 : view_(NULL) { | |
| 199 view_ = new MessageBubble(caption, message, message_type, anchor, arrow, | |
| 200 size_override, arrow_offset); | |
| 201 widget_ = view_->GetWidget(); | |
| 202 | |
| 203 gfx::NativeView native_view = widget_->GetNativeView(); | |
| 204 wm::SetWindowVisibilityAnimationType( | |
| 205 native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); | |
| 206 wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_HIDE); | |
| 207 view_->GetWidget()->Show(); | |
| 208 } | |
| 209 | |
| 210 PopupMessage::~PopupMessage() { | |
| 211 CancelHidingAnimation(); | |
| 212 Close(); | |
| 213 } | |
| 214 | |
| 215 void PopupMessage::Close() { | |
| 216 if (view_) { | |
| 217 view_->ClosePopup(); | |
| 218 view_ = NULL; | |
| 219 widget_ = NULL; | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 void PopupMessage::CancelHidingAnimation() { | |
| 224 if (!widget_ || !widget_->GetNativeView()) | |
| 225 return; | |
| 226 | |
| 227 gfx::NativeView native_view = widget_->GetNativeView(); | |
| 228 wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_NONE); | |
| 229 } | |
| 230 | |
| 231 } // namespace ash | |
| OLD | NEW |