diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-08 20:32:50 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-08 20:32:50 +0000 |
commit | e1fe3dafdb3fd61b6fbcff576cb625dcef2a71c2 (patch) | |
tree | c44cc0e27bc103d88b1da7a48c6bcaba9ae65526 | |
parent | 5f449baa69a92ea2ce4f62f5d10732e5c5dfc1ce (diff) | |
download | chromium_src-e1fe3dafdb3fd61b6fbcff576cb625dcef2a71c2.zip chromium_src-e1fe3dafdb3fd61b6fbcff576cb625dcef2a71c2.tar.gz chromium_src-e1fe3dafdb3fd61b6fbcff576cb625dcef2a71c2.tar.bz2 |
The start of the instant opt-in mocks.
I also had to make it so you can turn off animations in CustomButton.
BUG=54833
TEST=none
Review URL: http://codereview.chromium.org/3544015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62009 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/generated_resources.grd | 11 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_popup_model.h | 2 | ||||
-rw-r--r-- | chrome/browser/instant/instant_opt_in.cc | 20 | ||||
-rw-r--r-- | chrome/browser/instant/instant_opt_in.h | 23 | ||||
-rw-r--r-- | chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc | 141 | ||||
-rw-r--r-- | chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h | 8 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | views/controls/button/custom_button.cc | 8 | ||||
-rw-r--r-- | views/controls/button/custom_button.h | 11 |
9 files changed, 209 insertions, 17 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 48ee765..048d273 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4012,6 +4012,17 @@ Keep your key file in a safe place. You will need it to create new versions of y Enables a background service that connects the Google Cloud Print service to any printers installed on this computer. Once this lab is enabled, you can turn Cloud Print on by logging in with your Google account in the Options/Preferences in the Under the Hood section. </message> + <!-- Instant --> + <message name="IDS_INSTANT_OPT_IN_LABEL" desc="Label shown in the omnibox dropdown for enabling instant"> + Enable Instant for faster searching? + </message> + <message name="IDS_INSTANT_OPT_IN_ENABLE" desc="Button shown in the omnibox dropdown for enabling instant"> + Enable... + </message> + <message name="IDS_INSTANT_OPT_IN_NO_THANKS" desc="Button shown in the omnibox dropdodown for not enabling instant"> + No thanks + </message> + <!-- Click-to-load --> <message name="IDS_PLUGIN_LOAD" desc="The link for loading a blocked plug-in, displayed in the click-to-play UI."> Click to run this plug-in diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.h b/chrome/browser/autocomplete/autocomplete_popup_model.h index 5a7fe92..5d42a72 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_model.h +++ b/chrome/browser/autocomplete/autocomplete_popup_model.h @@ -119,6 +119,8 @@ class AutocompletePopupModel : public NotificationObserver { // use a standard style icon. const SkBitmap* GetSpecialIconForMatch(const AutocompleteMatch& match) const; + Profile* profile() const { return profile_; } + // The token value for selected_line_, hover_line_ and functions dealing with // a "line number" that indicates "no line". static const size_t kNoMatch = -1; diff --git a/chrome/browser/instant/instant_opt_in.cc b/chrome/browser/instant/instant_opt_in.cc new file mode 100644 index 0000000..611625a --- /dev/null +++ b/chrome/browser/instant/instant_opt_in.cc @@ -0,0 +1,20 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/instant/instant_opt_in.h" + +#include "chrome/browser/profile.h" + +namespace browser { + +bool ShouldShowInstantOptIn(Profile* profile) { + // TODO(sky): implement me. + return false; +} + +void UserPickedInstantOptIn(Profile* profile, bool opt_in) { + // TODO(sky): implement me. +} + +} // namespace browser diff --git a/chrome/browser/instant/instant_opt_in.h b/chrome/browser/instant/instant_opt_in.h new file mode 100644 index 0000000..a6505fb --- /dev/null +++ b/chrome/browser/instant/instant_opt_in.h @@ -0,0 +1,23 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_INSTANT_INSTANT_OPT_IN_H_ +#define CHROME_BROWSER_INSTANT_INSTANT_OPT_IN_H_ +#pragma once + +#include "base/basictypes.h" + +class Profile; + +namespace browser { + +// Returns true if the opt-in should be shown. +bool ShouldShowInstantOptIn(Profile* profile); + +// Invoked if the user clicks on the opt-in promo. +void UserPickedInstantOptIn(Profile* profile, bool opt_in); + +} // namespace browser + +#endif // CHROME_BROWSER_INSTANT_INSTANT_OPT_IN_H_ diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc index 7db0e42..a3b6071 100644 --- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc +++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc @@ -15,6 +15,7 @@ #include "base/i18n/rtl.h" #include "chrome/browser/autocomplete/autocomplete_edit_view.h" #include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/instant/instant_opt_in.h" #include "chrome/browser/views/bubble_border.h" #include "chrome/browser/views/location_bar/location_bar_view.h" #include "gfx/canvas_skia.h" @@ -24,6 +25,10 @@ #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "third_party/skia/include/core/SkShader.h" +#include "views/controls/button/text_button.h" +#include "views/controls/label.h" +#include "views/grid_layout.h" +#include "views/standard_layout.h" #include "views/widget/widget.h" #if defined(OS_WIN) @@ -117,7 +122,87 @@ const int kEditFontAdjust = -1; const int kEditFontAdjust = 0; #endif -} +// Horizontal padding between the buttons on the opt in promo. +const int kOptInButtonPadding = 2; + +// Padding around the opt in view. +const int kOptInLeftPadding = 12; +const int kOptInRightPadding = 0; +const int kOptInTopPadding = 6; +const int kOptInBottomPadding = 3; + +// Padding between the top of the opt-in view and the separator. +const int kOptInSeparatorSpacing = 2; + +} // namespace + +class AutocompletePopupContentsView::InstantOptInView : + public views::View, + public views::ButtonListener { + public: + InstantOptInView(AutocompletePopupContentsView* contents_view, + const gfx::Font& label_font, + const gfx::Font& button_font) + : contents_view_(contents_view) { + views::Label* label = + new views::Label(l10n_util::GetString(IDS_INSTANT_OPT_IN_LABEL)); + label->SetFont(label_font); + + views::GridLayout* layout = new views::GridLayout(this); + layout->SetInsets(kOptInTopPadding, kOptInLeftPadding, + kOptInBottomPadding, kOptInRightPadding); + SetLayoutManager(layout); + + const int first_column_set = 1; + views::GridLayout::Alignment v_align = views::GridLayout::CENTER; + views::ColumnSet* column_set = layout->AddColumnSet(first_column_set); + column_set->AddColumn(views::GridLayout::LEADING, v_align, 1, + views::GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(views::GridLayout::CENTER, v_align, 0, + views::GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kOptInButtonPadding); + column_set->AddColumn(views::GridLayout::CENTER, v_align, 0, + views::GridLayout::USE_PREF, 0, 0); + column_set->LinkColumnSizes(2, 4, -1); + layout->StartRow(0, first_column_set); + layout->AddView(label); + layout->AddView(CreateButton(IDS_INSTANT_OPT_IN_NO_THANKS, button_font)); + layout->AddView(CreateButton(IDS_INSTANT_OPT_IN_ENABLE, button_font)); + } + + virtual void ButtonPressed(views::Button* sender, const views::Event& event) { + contents_view_->UserPressedOptIn( + sender->tag() == IDS_INSTANT_OPT_IN_ENABLE); + // WARNING: we've been deleted. + } + + virtual void Paint(gfx::Canvas* canvas) { + canvas->DrawLineInt( + GetColor(NORMAL, DIMMED_TEXT), 0, kOptInSeparatorSpacing, width(), + kOptInSeparatorSpacing); + } + + private: + // Creates and returns a button configured for the opt-in promo. + views::View* CreateButton(int id, const gfx::Font& font) { + // NOTE: we can't use NativeButton as the popup is a layered window and + // native buttons don't draw in layered windows. + // TODO: these buttons look crap. Figure out the right border/background to + // use. + views::TextButton* button = + new views::TextButton(this, l10n_util::GetString(id)); + button->SetNormalHasBorder(true); + button->set_tag(IDS_INSTANT_OPT_IN_NO_THANKS); + button->SetFont(font); + button->set_animate_on_state_change(false); + return button; + } + + AutocompletePopupContentsView* contents_view_; + + DISALLOW_COPY_AND_ASSIGN(InstantOptInView); +}; class AutocompleteResultView : public views::View { public: @@ -630,7 +715,8 @@ AutocompletePopupContentsView::AutocompletePopupContentsView( result_font_(font.DeriveFont(kEditFontAdjust)), result_bold_font_(result_font_.DeriveFont(0, gfx::Font::BOLD)), ignore_mouse_drag_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(size_animation_(this)) { + ALLOW_THIS_IN_INITIALIZER_LIST(size_animation_(this)), + opt_in_view_(NULL) { // The following little dance is required because set_border() requires a // pointer to a non-const object. BubbleBorder* bubble_border = new BubbleBorder(BubbleBorder::NONE); @@ -689,19 +775,34 @@ void AutocompletePopupContentsView::UpdatePopupAppearance() { // Update the match cached by each row, in the process of doing so make sure // we have enough row views. int total_child_height = 0; - size_t child_view_count = GetChildViewCount(); + size_t child_rv_count = GetChildViewCount(); + if (opt_in_view_) { + DCHECK(child_rv_count > 0); + child_rv_count--; + } for (size_t i = 0; i < model_->result().size(); ++i) { AutocompleteResultView* result_view; - if (i >= child_view_count) { + if (i >= child_rv_count) { result_view = new AutocompleteResultView(this, i, result_font_, result_bold_font_); - AddChildView(result_view); + AddChildView(static_cast<int>(i), result_view); } else { result_view = static_cast<AutocompleteResultView*>(GetChildViewAt(i)); + result_view->SetVisible(true); } result_view->set_match(GetMatchAtIndex(i)); total_child_height += result_view->GetPreferredSize().height(); } + for (size_t i = model_->result().size(); i < child_rv_count; ++i) + GetChildViewAt(i)->SetVisible(false); + + if (!opt_in_view_ && browser::ShouldShowInstantOptIn(model_->profile())) { + opt_in_view_ = new InstantOptInView(this, result_bold_font_, result_font_); + AddChildView(opt_in_view_); + } + + if (opt_in_view_) + total_child_height += opt_in_view_->GetPreferredSize().height(); gfx::Rect new_target_bounds = CalculateTargetBounds(total_child_height); @@ -836,9 +937,11 @@ void AutocompletePopupContentsView::Layout() { int top = contents_rect.y(); for (int i = 0; i < child_count; ++i) { View* v = GetChildViewAt(i); - v->SetBounds(contents_rect.x(), top, contents_rect.width(), - v->GetPreferredSize().height()); - top = v->bounds().bottom(); + if (v->IsVisible()) { + v->SetBounds(contents_rect.x(), top, contents_rect.width(), + v->GetPreferredSize().height()); + top = v->bounds().bottom(); + } } // We need to manually schedule a paint here since we are a layered window and @@ -901,10 +1004,17 @@ bool AutocompletePopupContentsView::OnMouseDragged( } views::View* AutocompletePopupContentsView::GetViewForPoint( - const gfx::Point& /*point*/) { - // This View takes control of the mouse events, so it should be considered the - // active view for any point inside of it. - return this; + const gfx::Point& point) { + // If there is no opt in view, then we want all mouse events. Otherwise let + // any descendants of the opt-in view get mouse events. + if (!opt_in_view_) + return this; + + views::View* child = views::View::GetViewForPoint(point); + views::View* ancestor = child; + while (ancestor && ancestor != opt_in_view_) + ancestor = ancestor->GetParent(); + return ancestor ? child : this; } @@ -1027,3 +1137,10 @@ gfx::Rect AutocompletePopupContentsView::CalculateTargetBounds(int h) { return bubble_border_->GetBounds( location_bar_bounds, gfx::Size(location_bar_bounds.width(), h)); } + +void AutocompletePopupContentsView::UserPressedOptIn(bool opt_in) { + delete opt_in_view_; + opt_in_view_ = NULL; + browser::UserPickedInstantOptIn(model_->profile(), opt_in); + UpdatePopupAppearance(); +} diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h index 5253004..cf0640f 100644 --- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h +++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h @@ -95,6 +95,7 @@ class AutocompletePopupContentsView : public views::View, #else typedef AutocompletePopupGtk AutocompletePopupClass; #endif + class InstantOptInView; // Returns true if the model has a match at the specified index. bool HasMatchAt(size_t index) const; @@ -124,6 +125,10 @@ class AutocompletePopupContentsView : public views::View, // Returns the target bounds given the specified content height. gfx::Rect CalculateTargetBounds(int h); + // Invoked if the user clicks on one of the opt-in buttons. Removes the opt-in + // view. + void UserPressedOptIn(bool opt_in); + // The popup that contains this view. We create this, but it deletes itself // when its window is destroyed. This is a WeakPtr because it's possible for // the OS to destroy the window and thus delete this object before we're @@ -163,6 +168,9 @@ class AutocompletePopupContentsView : public views::View, gfx::Rect start_bounds_; gfx::Rect target_bounds_; + // If non-NULL the instant opt-in-view is visible. + views::View* opt_in_view_; + DISALLOW_COPY_AND_ASSIGN(AutocompletePopupContentsView); }; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a803bae..7f0094c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2079,6 +2079,8 @@ 'browser/instant/instant_loader_delegate.h', 'browser/instant/instant_loader_manager.cc', 'browser/instant/instant_loader_manager.h', + 'browser/instant/instant_opt_in.cc', + 'browser/instant/instant_opt_in.h', 'browser/intranet_redirect_detector.cc', 'browser/intranet_redirect_detector.h', 'browser/io_thread.cc', diff --git a/views/controls/button/custom_button.cc b/views/controls/button/custom_button.cc index a1f4e62..ebca6ff 100644 --- a/views/controls/button/custom_button.cc +++ b/views/controls/button/custom_button.cc @@ -23,8 +23,9 @@ void CustomButton::SetState(ButtonState state) { if (state == state_) return; - if (animate_on_state_change_ || !hover_animation_->is_animating()) { - animate_on_state_change_ = true; + if (animate_on_state_change_ && + (!is_throbbing_ || !hover_animation_->is_animating())) { + is_throbbing_ = false; if (state_ == BS_NORMAL && state == BS_HOT) { // Button is hovered from a normal state, start hover animation. hover_animation_->Show(); @@ -42,7 +43,7 @@ void CustomButton::SetState(ButtonState state) { } void CustomButton::StartThrobbing(int cycles_til_stop) { - animate_on_state_change_ = false; + is_throbbing_ = true; hover_animation_->StartThrobbing(cycles_til_stop); } @@ -109,6 +110,7 @@ CustomButton::CustomButton(ButtonListener* listener) : Button(listener), state_(BS_NORMAL), animate_on_state_change_(true), + is_throbbing_(false), triggerable_event_flags_(MouseEvent::EF_LEFT_BUTTON_DOWN), request_focus_on_press_(true) { hover_animation_.reset(new ThrobAnimation(this)); diff --git a/views/controls/button/custom_button.h b/views/controls/button/custom_button.h index f5a1b85..4de3bd6 100644 --- a/views/controls/button/custom_button.h +++ b/views/controls/button/custom_button.h @@ -63,6 +63,11 @@ class CustomButton : public Button, } bool request_focus_on_press() const { return request_focus_on_press_; } + // See description above field. + void set_animate_on_state_change(bool value) { + animate_on_state_change_ = value; + } + // Returns true if the mouse pointer is over this control. Note that this // isn't the same as IsHotTracked() because the mouse may be over the control // when it's disabled. @@ -108,10 +113,12 @@ class CustomButton : public Button, scoped_ptr<ThrobAnimation> hover_animation_; private: - // Should we animate when the state changes? Defaults to true, but false while - // throbbing. + // Should we animate when the state changes? Defaults to true. bool animate_on_state_change_; + // Is the hover animation running because StartThrob was invoked? + bool is_throbbing_; + // Mouse event flags which can trigger button actions. int triggerable_event_flags_; |