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 "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
9 #include "chrome/browser/themes/theme_properties.h"
10 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
11 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
12 #include "chrome/browser/ui/views/content_setting_bubble_contents.h"
13 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
14 #include "grit/theme_resources.h"
15 #include "ui/base/l10n/l10n_util.h"
16 #include "ui/base/resource/material_design/material_design_controller.h"
17 #include "ui/base/theme_provider.h"
18 #include "ui/gfx/color_utils.h"
19 #include "ui/views/controls/image_view.h"
20 #include "ui/views/controls/label.h"
21 #include "ui/views/widget/widget.h"
25 // Time spent with animation fully open.
26 const int kStayOpenTimeMS
= 3200;
31 const int ContentSettingImageView::kOpenTimeMS
= 150;
32 const int ContentSettingImageView::kAnimationDurationMS
=
33 (kOpenTimeMS
* 2) + kStayOpenTimeMS
;
35 ContentSettingImageView::ContentSettingImageView(
36 ContentSettingsType content_type
,
37 LocationBarView
* parent
,
38 const gfx::FontList
& font_list
,
40 SkColor parent_background_color
)
41 : IconLabelBubbleView(0,
44 parent_background_color
,
47 content_setting_image_model_(
48 ContentSettingImageModel::CreateContentSettingImageModel(
50 slide_animator_(this),
51 pause_animation_(false),
52 pause_animation_state_(0.0),
53 bubble_widget_(NULL
) {
54 if (ui::MaterialDesignController::IsModeMaterial()) {
55 // The insets for IDR_OMNIBOX_CONTENT_SETTING_BUBBLE for which to perfom
57 static const int kImageInset
= 4;
58 gfx::Insets
insets(kImageInset
, kImageInset
, kImageInset
, kImageInset
);
59 SetBackgroundImageWithInsets(IDR_OMNIBOX_CONTENT_SETTING_BUBBLE
, insets
);
61 static const int kBackgroundImages
[] =
62 IMAGE_GRID(IDR_OMNIBOX_CONTENT_SETTING_BUBBLE
);
63 SetBackgroundImageGrid(kBackgroundImages
);
66 image()->SetHorizontalAlignment(views::ImageView::LEADING
);
67 image()->set_interactive(true);
68 label()->SetElideBehavior(gfx::NO_ELIDE
);
70 slide_animator_
.SetSlideDuration(kAnimationDurationMS
);
71 slide_animator_
.SetTweenType(gfx::Tween::LINEAR
);
74 ContentSettingImageView::~ContentSettingImageView() {
76 bubble_widget_
->RemoveObserver(this);
79 void ContentSettingImageView::Update(content::WebContents
* web_contents
) {
80 // Note: We explicitly want to call this even if |web_contents| is NULL, so we
81 // get hidden properly while the user is editing the omnibox.
82 content_setting_image_model_
->UpdateFromWebContents(web_contents
);
84 if (!content_setting_image_model_
->is_visible()) {
89 SetImage(content_setting_image_model_
->icon().AsImageSkia());
90 image()->SetTooltipText(
91 base::UTF8ToUTF16(content_setting_image_model_
->get_tooltip()));
94 // If the content blockage should be indicated to the user, start the
95 // animation and record that we indicated the blockage.
96 TabSpecificContentSettings
* content_settings
= web_contents
?
97 TabSpecificContentSettings::FromWebContents(web_contents
) : NULL
;
98 if (!content_settings
|| content_settings
->IsBlockageIndicated(
99 content_setting_image_model_
->get_content_settings_type()))
102 // We just ignore this blockage if we're already showing some other string to
103 // the user. If this becomes a problem, we could design some sort of queueing
104 // mechanism to show one after the other, but it doesn't seem important now.
105 int string_id
= content_setting_image_model_
->explanatory_string_id();
106 if (string_id
&& !ShouldShowBackground()) {
107 SetLabel(l10n_util::GetStringUTF16(string_id
));
108 label()->SetVisible(true);
109 slide_animator_
.Show();
112 content_settings
->SetBlockageHasBeenIndicated(
113 content_setting_image_model_
->get_content_settings_type());
116 bool ContentSettingImageView::ShouldShowBackground() const {
117 return slide_animator_
.is_animating() || pause_animation_
;
120 double ContentSettingImageView::WidthMultiplier() const {
121 double state
= slide_animator_
.GetCurrentValue();
122 // The fraction of the animation we'll spend animating the string into view,
123 // which is also the fraction we'll spend animating it closed; total
124 // animation (slide out, show, then slide in) is 1.0.
125 const double kOpenFraction
=
126 static_cast<double>(kOpenTimeMS
) / kAnimationDurationMS
;
127 double size_fraction
= 1.0;
128 if (state
< kOpenFraction
)
129 size_fraction
= state
/ kOpenFraction
;
130 if (state
> (1.0 - kOpenFraction
))
131 size_fraction
= (1.0 - state
) / kOpenFraction
;
132 return size_fraction
;
135 void ContentSettingImageView::AnimationEnded(const gfx::Animation
* animation
) {
136 slide_animator_
.Reset();
137 if (!pause_animation_
) {
138 label()->SetVisible(false);
140 parent_
->SchedulePaint();
144 void ContentSettingImageView::AnimationProgressed(
145 const gfx::Animation
* animation
) {
146 if (!pause_animation_
) {
148 parent_
->SchedulePaint();
152 void ContentSettingImageView::AnimationCanceled(
153 const gfx::Animation
* animation
) {
154 AnimationEnded(animation
);
157 const char* ContentSettingImageView::GetClassName() const {
158 return "ContentSettingsImageView";
161 bool ContentSettingImageView::OnMousePressed(const ui::MouseEvent
& event
) {
162 // We want to show the bubble on mouse release; that is the standard behavior
167 void ContentSettingImageView::OnMouseReleased(const ui::MouseEvent
& event
) {
168 if (HitTestPoint(event
.location()))
172 void ContentSettingImageView::OnGestureEvent(ui::GestureEvent
* event
) {
173 if (event
->type() == ui::ET_GESTURE_TAP
)
175 if ((event
->type() == ui::ET_GESTURE_TAP
) ||
176 (event
->type() == ui::ET_GESTURE_TAP_DOWN
))
180 void ContentSettingImageView::OnWidgetDestroying(views::Widget
* widget
) {
181 DCHECK_EQ(bubble_widget_
, widget
);
182 bubble_widget_
->RemoveObserver(this);
183 bubble_widget_
= NULL
;
185 if (pause_animation_
) {
186 slide_animator_
.Reset(pause_animation_state_
);
187 pause_animation_
= false;
188 slide_animator_
.Show();
192 void ContentSettingImageView::OnClick() {
193 if (slide_animator_
.is_animating()) {
194 if (!pause_animation_
) {
195 pause_animation_
= true;
196 pause_animation_state_
= slide_animator_
.GetCurrentValue();
198 slide_animator_
.Reset();
201 content::WebContents
* web_contents
= parent_
->GetWebContents();
202 if (web_contents
&& !bubble_widget_
) {
204 parent_
->delegate()->CreateViewsBubble(new ContentSettingBubbleContents(
205 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
206 parent_
->delegate()->GetContentSettingBubbleModelDelegate(),
207 web_contents
, parent_
->profile(),
208 content_setting_image_model_
->get_content_settings_type()),
209 web_contents
, this, views::BubbleBorder::TOP_RIGHT
));
210 bubble_widget_
->AddObserver(this);
211 bubble_widget_
->Show();