search_box_view.cc revision 3551c9c881056c480085172ff9840cab31610854
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.
4
5#include "ui/app_list/views/search_box_view.h"
6
7#include <algorithm>
8
9#include "grit/ui_resources.h"
10#include "ui/app_list/app_list_model.h"
11#include "ui/app_list/search_box_model.h"
12#include "ui/app_list/views/app_list_menu_views.h"
13#include "ui/app_list/views/search_box_view_delegate.h"
14#include "ui/base/events/event.h"
15#include "ui/base/resource/resource_bundle.h"
16#include "ui/views/controls/button/menu_button.h"
17#include "ui/views/controls/image_view.h"
18#include "ui/views/controls/textfield/textfield.h"
19
20namespace app_list {
21
22namespace {
23
24const int kPadding = 14;
25const int kIconDimension = 32;
26const int kPreferredWidth = 360;
27const int kPreferredHeight = 48;
28const int kMenuButtonDimension = 29;
29
30const SkColor kHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0);
31
32// Menu offset relative to the bottom-right corner of the menu button.
33const int kMenuYOffsetFromButton = -4;
34const int kMenuXOffsetFromButton = -7;
35
36}  // namespace
37
38SearchBoxView::SearchBoxView(SearchBoxViewDelegate* delegate,
39                             AppListViewDelegate* view_delegate,
40                             AppListModel* model)
41    : delegate_(delegate),
42      view_delegate_(view_delegate),
43      model_(model),
44      icon_view_(new views::ImageView),
45      search_box_(new views::Textfield),
46      contents_view_(NULL) {
47  DCHECK(model_);
48  AddChildView(icon_view_);
49
50  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
51
52#if !defined(OS_CHROMEOS)
53  menu_button_ = new views::MenuButton(NULL, base::string16(), this, false);
54  menu_button_->set_border(NULL);
55  menu_button_->SetIcon(*rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_NORMAL));
56  menu_button_->SetHoverIcon(*rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_HOVER));
57  menu_button_->SetPushedIcon(*rb.GetImageSkiaNamed(
58      IDR_APP_LIST_TOOLS_PRESSED));
59  AddChildView(menu_button_);
60#endif
61
62  search_box_->RemoveBorder();
63  search_box_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
64  search_box_->set_placeholder_text_color(kHintTextColor);
65  search_box_->SetController(this);
66  AddChildView(search_box_);
67
68  model_->search_box()->AddObserver(this);
69  IconChanged();
70  HintTextChanged();
71}
72
73SearchBoxView::~SearchBoxView() {
74  model_->search_box()->RemoveObserver(this);
75}
76
77bool SearchBoxView::HasSearch() const {
78  return !search_box_->text().empty();
79}
80
81void SearchBoxView::ClearSearch() {
82  search_box_->SetText(base::string16());
83  // Updates model and fires query changed manually because SetText() above
84  // does not generate ContentsChanged() notification.
85  UpdateModel();
86  NotifyQueryChanged();
87}
88
89void SearchBoxView::InvalidateMenu() {
90  menu_.reset();
91}
92
93gfx::Size SearchBoxView::GetPreferredSize() {
94  return gfx::Size(kPreferredWidth, kPreferredHeight);
95}
96
97void SearchBoxView::Layout() {
98  gfx::Rect rect(GetContentsBounds());
99  if (rect.IsEmpty())
100    return;
101
102  gfx::Rect icon_frame(rect);
103  icon_frame.set_width(kIconDimension + 2 * kPadding);
104  icon_view_->SetBoundsRect(icon_frame);
105
106  gfx::Rect menu_button_frame(rect);
107#if !defined(OS_CHROMEOS)
108  menu_button_frame.set_width(kMenuButtonDimension);
109  menu_button_frame.set_x(rect.right() - menu_button_frame.width() - kPadding);
110  menu_button_frame.ClampToCenteredSize(gfx::Size(menu_button_frame.width(),
111                                                  kMenuButtonDimension));
112  menu_button_->SetBoundsRect(menu_button_frame);
113#else
114  menu_button_frame.set_width(0);
115#endif
116
117  gfx::Rect edit_frame(rect);
118  edit_frame.set_x(icon_frame.right());
119  edit_frame.set_width(
120      rect.width() - icon_frame.width() - kPadding - menu_button_frame.width());
121  edit_frame.ClampToCenteredSize(
122      gfx::Size(edit_frame.width(), search_box_->GetPreferredSize().height()));
123  search_box_->SetBoundsRect(edit_frame);
124}
125
126bool SearchBoxView::OnMouseWheel(const ui::MouseWheelEvent& event) {
127  if (contents_view_)
128    return contents_view_->OnMouseWheel(event);
129
130  return false;
131}
132
133void SearchBoxView::UpdateModel() {
134  // Temporarily remove from observer to ignore notifications caused by us.
135  model_->search_box()->RemoveObserver(this);
136  model_->search_box()->SetText(search_box_->text());
137  model_->search_box()->SetSelectionModel(search_box_->GetSelectionModel());
138  model_->search_box()->AddObserver(this);
139}
140
141void SearchBoxView::NotifyQueryChanged() {
142  DCHECK(delegate_);
143  delegate_->QueryChanged(this);
144}
145
146void SearchBoxView::ContentsChanged(views::Textfield* sender,
147                                    const base::string16& new_contents) {
148  UpdateModel();
149  NotifyQueryChanged();
150}
151
152bool SearchBoxView::HandleKeyEvent(views::Textfield* sender,
153                                   const ui::KeyEvent& key_event) {
154  bool handled = false;
155  if (contents_view_ && contents_view_->visible())
156    handled = contents_view_->OnKeyPressed(key_event);
157
158  return handled;
159}
160
161void SearchBoxView::OnMenuButtonClicked(View* source, const gfx::Point& point) {
162  if (!menu_)
163    menu_.reset(new AppListMenuViews(view_delegate_, model_));
164
165  const gfx::Point menu_location =
166      menu_button_->GetBoundsInScreen().bottom_right() +
167      gfx::Vector2d(kMenuXOffsetFromButton, kMenuYOffsetFromButton);
168  menu_->RunMenuAt(menu_button_, menu_location);
169}
170
171void SearchBoxView::IconChanged() {
172  icon_view_->SetImage(model_->search_box()->icon());
173}
174
175void SearchBoxView::HintTextChanged() {
176  search_box_->set_placeholder_text(model_->search_box()->hint_text());
177}
178
179void SearchBoxView::SelectionModelChanged() {
180  search_box_->SelectSelectionModel(model_->search_box()->selection_model());
181}
182
183void SearchBoxView::TextChanged() {
184  search_box_->SetText(model_->search_box()->text());
185}
186
187}  // namespace app_list
188