summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-28 23:48:14 +0000
committerderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-28 23:48:14 +0000
commit814e3e2f12f8c67228e0c4613c8149f30177b9dc (patch)
tree278adf6a4cd4d3638323bc25b76acebb43fdd892 /ui
parentda36da98ce283c09d7b1cbdd3d2450df72ca659c (diff)
downloadchromium_src-814e3e2f12f8c67228e0c4613c8149f30177b9dc.zip
chromium_src-814e3e2f12f8c67228e0c4613c8149f30177b9dc.tar.gz
chromium_src-814e3e2f12f8c67228e0c4613c8149f30177b9dc.tar.bz2
ash: Add support for additional icons in apps search list.
This adds the concept of "action icons" to app_list::SearchResult. These are small icons that appear at the right of a given search result and can be clicked to invoke alternate actions. I'm planning to use this to expose chat, call, email, etc. actions for contact results. BUG=141877 TEST=none Review URL: https://chromiumcodereview.appspot.com/10872099 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@153795 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/app_list/app_list_view.cc7
-rw-r--r--ui/app_list/app_list_view.h3
-rw-r--r--ui/app_list/app_list_view_delegate.h6
-rw-r--r--ui/app_list/search_result.cc20
-rw-r--r--ui/app_list/search_result.h32
-rw-r--r--ui/app_list/search_result_list_view.cc31
-rw-r--r--ui/app_list/search_result_list_view.h17
-rw-r--r--ui/app_list/search_result_list_view_delegate.h6
-rw-r--r--ui/app_list/search_result_observer.h5
-rw-r--r--ui/app_list/search_result_view.cc87
-rw-r--r--ui/app_list/search_result_view.h16
-rw-r--r--ui/app_list/search_result_view_delegate.h34
12 files changed, 231 insertions, 33 deletions
diff --git a/ui/app_list/app_list_view.cc b/ui/app_list/app_list_view.cc
index d0b56e4..d1c0b43 100644
--- a/ui/app_list/app_list_view.cc
+++ b/ui/app_list/app_list_view.cc
@@ -193,4 +193,11 @@ void AppListView::OpenResult(const SearchResult& result, int event_flags) {
delegate_->OpenSearchResult(result, event_flags);
}
+void AppListView::InvokeResultAction(const SearchResult& result,
+ int action_index,
+ int event_flags) {
+ if (delegate_.get())
+ delegate_->InvokeSearchResultAction(result, action_index, event_flags);
+}
+
} // namespace app_list
diff --git a/ui/app_list/app_list_view.h b/ui/app_list/app_list_view.h
index 5bdebe6..708d55a 100644
--- a/ui/app_list/app_list_view.h
+++ b/ui/app_list/app_list_view.h
@@ -70,6 +70,9 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView,
// Overridden from SearchResultListViewDelegate:
virtual void OpenResult(const SearchResult& result,
int event_flags) OVERRIDE;
+ virtual void InvokeResultAction(const SearchResult& result,
+ int action_index,
+ int event_flags) OVERRIDE;
scoped_ptr<AppListModel> model_;
scoped_ptr<AppListViewDelegate> delegate_;
diff --git a/ui/app_list/app_list_view_delegate.h b/ui/app_list/app_list_view_delegate.h
index 159d616..d7e0c82 100644
--- a/ui/app_list/app_list_view_delegate.h
+++ b/ui/app_list/app_list_view_delegate.h
@@ -38,6 +38,12 @@ class APP_LIST_EXPORT AppListViewDelegate {
virtual void OpenSearchResult(const SearchResult& result,
int event_flags) = 0;
+ // Called to invoke a custom action on |result|. |action_index| corresponds
+ // to the index of an icon in |result.action_icons()|.
+ virtual void InvokeSearchResultAction(const SearchResult& result,
+ int action_index,
+ int event_flags) = 0;
+
// Invoked to close app list.
virtual void Close() = 0;
};
diff --git a/ui/app_list/search_result.cc b/ui/app_list/search_result.cc
index b0704fb..597ea60 100644
--- a/ui/app_list/search_result.cc
+++ b/ui/app_list/search_result.cc
@@ -8,6 +8,19 @@
namespace app_list {
+SearchResult::ActionIconSet::ActionIconSet(const gfx::ImageSkia& base_image,
+ const gfx::ImageSkia& hover_image,
+ const gfx::ImageSkia& pressed_image,
+ const string16& tooltip_text)
+ : base_image(base_image),
+ hover_image(hover_image),
+ pressed_image(pressed_image),
+ tooltip_text(tooltip_text) {
+}
+
+SearchResult::ActionIconSet::~ActionIconSet() {
+}
+
SearchResult::SearchResult() {
}
@@ -21,6 +34,13 @@ void SearchResult::SetIcon(const gfx::ImageSkia& icon) {
OnIconChanged());
}
+void SearchResult::SetActionIcons(const std::vector<ActionIconSet>& sets) {
+ action_icons_ = sets;
+ FOR_EACH_OBSERVER(SearchResultObserver,
+ observers_,
+ OnActionIconsChanged());
+}
+
void SearchResult::AddObserver(SearchResultObserver* observer) {
observers_.AddObserver(observer);
}
diff --git a/ui/app_list/search_result.h b/ui/app_list/search_result.h
index f96d8d4..c7b2760 100644
--- a/ui/app_list/search_result.h
+++ b/ui/app_list/search_result.h
@@ -45,12 +45,26 @@ class APP_LIST_EXPORT SearchResult {
};
typedef std::vector<Tag> Tags;
+ // A collection of images representing an action that can be performed on this
+ // search result.
+ struct ActionIconSet {
+ ActionIconSet(const gfx::ImageSkia& base_image,
+ const gfx::ImageSkia& hover_image,
+ const gfx::ImageSkia& pressed_image,
+ const string16& tooltip_text);
+ ~ActionIconSet();
+
+ gfx::ImageSkia base_image;
+ gfx::ImageSkia hover_image;
+ gfx::ImageSkia pressed_image;
+
+ string16 tooltip_text;
+ };
+ typedef std::vector<ActionIconSet> ActionIconSets;
+
SearchResult();
virtual ~SearchResult();
- void AddObserver(SearchResultObserver* observer);
- void RemoveObserver(SearchResultObserver* observer);
-
const gfx::ImageSkia& icon() const { return icon_; }
void SetIcon(const gfx::ImageSkia& icon);
@@ -66,6 +80,14 @@ class APP_LIST_EXPORT SearchResult {
const Tags& details_tags() const { return details_tags_; }
void set_details_tags(const Tags& tags) { details_tags_ = tags; }
+ const ActionIconSets& action_icons() const {
+ return action_icons_;
+ }
+ void SetActionIcons(const ActionIconSets& sets);
+
+ void AddObserver(SearchResultObserver* observer);
+ void RemoveObserver(SearchResultObserver* observer);
+
private:
gfx::ImageSkia icon_;
@@ -75,6 +97,10 @@ class APP_LIST_EXPORT SearchResult {
string16 details_;
Tags details_tags_;
+ // Optional list of icons representing additional actions that can be
+ // performed on this result.
+ ActionIconSets action_icons_;
+
ObserverList<SearchResultObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(SearchResult);
diff --git a/ui/app_list/search_result_list_view.cc b/ui/app_list/search_result_list_view.cc
index 64df98a..d5d9647 100644
--- a/ui/app_list/search_result_list_view.cc
+++ b/ui/app_list/search_result_list_view.cc
@@ -83,7 +83,7 @@ bool SearchResultListView::OnKeyPressed(const ui::KeyEvent& event) {
return true;
case ui::VKEY_RETURN:
if (selected_index_ >= 0)
- ButtonPressed(GetResultViewAt(selected_index_), event);
+ SearchResultActivated(GetResultViewAt(selected_index_), event);
return true;
default:
break;
@@ -127,20 +127,6 @@ void SearchResultListView::ScheduleUpdate() {
}
}
-void SearchResultListView::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- if (sender->GetClassName() != SearchResultView::kViewClassName)
- return;
-
- if (delegate_) {
- const SearchResult* result =
- static_cast<SearchResultView*>(sender)->result();
-
- if (result)
- delegate_->OpenResult(*result, event.flags());
- }
-}
-
void SearchResultListView::ListItemsAdded(size_t start, size_t count) {
ScheduleUpdate();
}
@@ -157,4 +143,19 @@ void SearchResultListView::ListItemsChanged(size_t start, size_t count) {
ScheduleUpdate();
}
+void SearchResultListView::SearchResultActivated(SearchResultView* view,
+ const ui::Event& event) {
+ if (delegate_ && view->result())
+ delegate_->OpenResult(*(view->result()), event.flags());
+}
+
+void SearchResultListView::SearchResultActionActivated(SearchResultView* view,
+ int action_index,
+ const ui::Event& event) {
+ if (delegate_ && view->result()) {
+ delegate_->InvokeResultAction(
+ *(view->result()), action_index, event.flags());
+ }
+}
+
} // namespace app_list
diff --git a/ui/app_list/search_result_list_view.h b/ui/app_list/search_result_list_view.h
index 90311d5..8f0ca93 100644
--- a/ui/app_list/search_result_list_view.h
+++ b/ui/app_list/search_result_list_view.h
@@ -8,8 +8,8 @@
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "ui/app_list/app_list_model.h"
+#include "ui/app_list/search_result_view_delegate.h"
#include "ui/base/models/list_model_observer.h"
-#include "ui/views/controls/button/button.h"
#include "ui/views/view.h"
namespace app_list {
@@ -20,8 +20,8 @@ class SearchResultView;
// SearchResultListView displays AppListModel::SearchResults with a list of
// SearchResultView.
class SearchResultListView : public views::View,
- public views::ButtonListener,
- public ui::ListModelObserver {
+ public ui::ListModelObserver,
+ public SearchResultViewDelegate {
public:
explicit SearchResultListView(SearchResultListViewDelegate* delegate);
virtual ~SearchResultListView();
@@ -46,15 +46,18 @@ class SearchResultListView : public views::View,
// pending call.
void ScheduleUpdate();
- // Overridden from views::ButtonListener:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
// Overridden from ListModelObserver:
virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
+ // Overridden from SearchResultViewDelegate:
+ virtual void SearchResultActivated(SearchResultView* view,
+ const ui::Event& event) OVERRIDE;
+ virtual void SearchResultActionActivated(SearchResultView* view,
+ int action_index,
+ const ui::Event& event) OVERRIDE;
+
SearchResultListViewDelegate* delegate_; // Not owned.
AppListModel::SearchResults* results_; // Owned by AppListModel.
diff --git a/ui/app_list/search_result_list_view_delegate.h b/ui/app_list/search_result_list_view_delegate.h
index 419bb3e..3022e3f 100644
--- a/ui/app_list/search_result_list_view_delegate.h
+++ b/ui/app_list/search_result_list_view_delegate.h
@@ -19,6 +19,12 @@ class APP_LIST_EXPORT SearchResultListViewDelegate {
virtual void OpenResult(const SearchResult& result,
int event_flags) = 0;
+ // Called to invoke a custom action on |result|. |action_index| corresponds
+ // to the index of the icon in |result.action_icons()| that was activated.
+ virtual void InvokeResultAction(const SearchResult& result,
+ int action_index,
+ int event_flags) = 0;
+
protected:
virtual ~SearchResultListViewDelegate() {}
};
diff --git a/ui/app_list/search_result_observer.h b/ui/app_list/search_result_observer.h
index e539c72..b78c054 100644
--- a/ui/app_list/search_result_observer.h
+++ b/ui/app_list/search_result_observer.h
@@ -11,9 +11,12 @@ namespace app_list {
class APP_LIST_EXPORT SearchResultObserver {
public:
- // Invoked when SearchResult icon has changed.
+ // Invoked when the SearchResult's icon has changed.
virtual void OnIconChanged() = 0;
+ // Invoked when the SearchResult's action icons have been changed.
+ virtual void OnActionIconsChanged() = 0;
+
protected:
virtual ~SearchResultObserver() {}
};
diff --git a/ui/app_list/search_result_view.cc b/ui/app_list/search_result_view.cc
index 7c71e8e..98f7405 100644
--- a/ui/app_list/search_result_view.cc
+++ b/ui/app_list/search_result_view.cc
@@ -8,7 +8,9 @@
#include "ui/app_list/search_result_list_view.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
+#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/render_text.h"
+#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
namespace {
@@ -21,6 +23,15 @@ const int kIconViewWidth = kIconDimension + 2 * kIconPadding;
const int kTextTrailPadding = kIconPadding;
const int kBorderSize = 1;
+// Maximum dimensions of a search result's action icons.
+const int kActionIconDimension = 24;
+
+// Total space (including padding) used for each action icon's button.
+const int kActionButtonWidth = 32;
+
+// Extra margin at the right of the rightmost action icon.
+const int kActionButtonRightMargin = 8;
+
const SkColor kBorderColor = SkColorSetARGB(0x0F, 0, 0, 0);
const SkColor kDefaultTextColor = SkColorSetRGB(0x33, 0x33, 0x33);
@@ -89,10 +100,11 @@ namespace app_list {
const char SearchResultView::kViewClassName[] = "ui/app_list/SearchResultView";
SearchResultView::SearchResultView(SearchResultListView* list_view,
- views::ButtonListener* listener)
- : views::CustomButton(listener),
+ SearchResultViewDelegate* delegate)
+ : views::CustomButton(this),
result_(NULL),
list_view_(list_view),
+ delegate_(delegate),
icon_(new IconView) {
AddChildView(icon_);
}
@@ -109,6 +121,7 @@ void SearchResultView::SetResult(SearchResult* result) {
result_->AddObserver(this);
OnIconChanged();
+ OnActionIconsChanged();
UpdateTitleText();
UpdateDetailsText();
SchedulePaint();
@@ -155,6 +168,17 @@ void SearchResultView::Layout() {
icon_bounds.set_width(kIconViewWidth);
icon_bounds.Inset(kIconPadding, (rect.height() - kIconDimension) / 2);
icon_->SetBoundsRect(icon_bounds.Intersect(rect));
+
+ size_t num_buttons = action_buttons_.size();
+ for (size_t i = 0; i < num_buttons; ++i) {
+ views::ImageButton* button = action_buttons_[i];
+ gfx::Rect button_bounds(
+ rect.right() - kActionButtonRightMargin -
+ (num_buttons - i) * kActionButtonWidth,
+ (rect.y() + rect.height() - kActionIconDimension) / 2,
+ kActionButtonWidth, kActionIconDimension);
+ button->SetBoundsRect(button_bounds);
+ }
}
void SearchResultView::OnPaint(gfx::Canvas* canvas) {
@@ -178,7 +202,10 @@ void SearchResultView::OnPaint(gfx::Canvas* canvas) {
gfx::Rect text_bounds(rect);
text_bounds.set_x(kIconViewWidth);
- text_bounds.set_width(rect.width() - kIconViewWidth - kTextTrailPadding);
+ text_bounds.set_width(
+ rect.width() - kIconViewWidth - kTextTrailPadding -
+ action_buttons_.size() * kActionButtonWidth -
+ (!action_buttons_.empty() ? kActionButtonRightMargin : 0));
if (title_text_.get() && details_text_.get()) {
gfx::Size title_size(text_bounds.width(),
@@ -204,6 +231,22 @@ void SearchResultView::OnPaint(gfx::Canvas* canvas) {
}
}
+void SearchResultView::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ if (sender == this) {
+ delegate_->SearchResultActivated(this, event);
+ return;
+ }
+
+ for (size_t i = 0; i < action_buttons_.size(); ++i) {
+ if (sender == action_buttons_[i]) {
+ delegate_->SearchResultActionActivated(this, i, event);
+ return;
+ }
+ }
+ NOTREACHED() << "Got unexpected button press on " << sender;
+}
+
void SearchResultView::OnIconChanged() {
gfx::ImageSkia image(result_ ? result_->icon() : gfx::ImageSkia());
// Note this might leave the view with an old icon. But it is needed to avoid
@@ -215,12 +258,44 @@ void SearchResultView::OnIconChanged() {
return;
// Scales down big icons but leave small ones unchanged.
- if (image.width() > kIconDimension || image.height() > kIconDimension)
- icon_->SetImageSize(gfx::Size(kIconDimension, kIconDimension));
- else
+ if (image.width() > kIconDimension || image.height() > kIconDimension) {
+ image = gfx::ImageSkiaOperations::CreateResizedImage(
+ image,
+ skia::ImageOperations::RESIZE_BEST,
+ gfx::Size(kIconDimension, kIconDimension));
+ } else {
icon_->ResetImageSize();
+ }
icon_->SetImage(image);
}
+void SearchResultView::OnActionIconsChanged() {
+ while (action_buttons_.size() >
+ (result_ ? result_->action_icons().size() : 0)) {
+ RemoveChildView(action_buttons_.back());
+ action_buttons_.pop_back();
+ }
+
+ if (result_) {
+ while (action_buttons_.size() < result_->action_icons().size()) {
+ views::ImageButton* button = new views::ImageButton(this);
+ button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+ views::ImageButton::ALIGN_MIDDLE);
+ AddChildView(button);
+ action_buttons_.push_back(button);
+ }
+
+ const SearchResult::ActionIconSets& icons = result_->action_icons();
+ for (size_t i = 0; i < icons.size(); ++i) {
+ const SearchResult::ActionIconSet& icon = icons.at(i);
+ views::ImageButton* button = action_buttons_[i];
+ button->SetImage(views::CustomButton::BS_NORMAL, &icon.base_image);
+ button->SetImage(views::CustomButton::BS_HOT, &icon.hover_image);
+ button->SetImage(views::CustomButton::BS_PUSHED, &icon.pressed_image);
+ button->SetTooltipText(icon.tooltip_text);
+ }
+ }
+}
+
} // namespace app_list
diff --git a/ui/app_list/search_result_view.h b/ui/app_list/search_result_view.h
index 78627ef..c8a373f 100644
--- a/ui/app_list/search_result_view.h
+++ b/ui/app_list/search_result_view.h
@@ -17,6 +17,7 @@ class RenderText;
}
namespace views {
+class ImageButton;
class ImageView;
}
@@ -24,16 +25,18 @@ namespace app_list {
class SearchResult;
class SearchResultListView;
+class SearchResultViewDelegate;
// SearchResultView displays a SearchResult.
class SearchResultView : public views::CustomButton,
+ public views::ButtonListener,
public SearchResultObserver {
public:
// Internal class name.
static const char kViewClassName[];
SearchResultView(SearchResultListView* list_view,
- views::ButtonListener* listener);
+ SearchResultViewDelegate* delegate);
virtual ~SearchResultView();
// Sets/gets SearchResult displayed by this view.
@@ -53,18 +56,29 @@ class SearchResultView : public views::CustomButton,
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ // views::ButtonListener overrides:
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE;
+
// SearchResultObserver overrides:
virtual void OnIconChanged() OVERRIDE;
+ virtual void OnActionIconsChanged() OVERRIDE;
SearchResult* result_; // Owned by AppListModel::SearchResults.
// Parent list view. Owned by views hierarchy.
SearchResultListView* list_view_;
+ // Not owned by us.
+ SearchResultViewDelegate* delegate_;
+
views::ImageView* icon_; // Owned by views hierarchy.
scoped_ptr<gfx::RenderText> title_text_;
scoped_ptr<gfx::RenderText> details_text_;
+ // Owned by the views hierarchy.
+ std::vector<views::ImageButton*> action_buttons_;
+
DISALLOW_COPY_AND_ASSIGN(SearchResultView);
};
diff --git a/ui/app_list/search_result_view_delegate.h b/ui/app_list/search_result_view_delegate.h
new file mode 100644
index 0000000..9b4b467
--- /dev/null
+++ b/ui/app_list/search_result_view_delegate.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 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 UI_APP_LIST_SEARCH_RESULT_VIEW_DELEGATE_H_
+#define UI_APP_LIST_SEARCH_RESULT_VIEW_DELEGATE_H_
+
+namespace ui {
+class Event;
+}
+
+namespace app_list {
+
+class SearchResultView;
+
+class SearchResultViewDelegate {
+ public:
+ // Called when the search result is activated.
+ virtual void SearchResultActivated(SearchResultView* view,
+ const ui::Event& event) = 0;
+
+ // Called when one of the search result's optional action icons is activated.
+ // |action_index| contains the 0-based index of the action.
+ virtual void SearchResultActionActivated(SearchResultView* view,
+ int action_index,
+ const ui::Event& event) = 0;
+
+ protected:
+ virtual ~SearchResultViewDelegate() {}
+};
+
+} // namespace ash
+
+#endif // UI_APP_LIST_SEARCH_RESULT_VIEW_DELEGATE_H_