Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: chrome/browser/ui/views/omnibox/inline_omnibox_popup_view.cc

Issue 10580039: Adds ability to render omnibox as a view above the page. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix windows Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
Peter Kasting 2012/06/22 20:33:22 It would have been nice to copy this file from omn
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 "chrome/browser/ui/views/omnibox/inline_omnibox_popup_view.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/omnibox/omnibox_view.h"
11 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
12 #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
13 #include "grit/chromium_strings.h"
14 #include "grit/generated_resources.h"
15 #include "grit/theme_resources.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/base/layout.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/base/theme_provider.h"
20 #include "ui/gfx/canvas.h"
21 #include "ui/gfx/insets.h"
22 #include "ui/gfx/path.h"
23 #include "ui/views/background.h"
24 #include "ui/views/controls/button/text_button.h"
25 #include "ui/views/controls/label.h"
26 #include "ui/views/layout/layout_constants.h"
27 #include "ui/views/painter.h"
28 #include "ui/views/widget/widget.h"
29 #include "unicode/ubidi.h"
30
31 namespace {
32
33 // The size delta between the font used for the edit and the result rows. Passed
34 // to gfx::Font::DeriveFont.
35 #if defined(OS_CHROMEOS)
36 // Don't adjust the size on Chrome OS (http://crbug.com/61433).
37 const int kEditFontAdjust = 0;
38 #else
39 const int kEditFontAdjust = -1;
40 #endif
41
42 } // namespace
43
44 InlineOmniboxPopupView::InlineOmniboxPopupView(
45 const gfx::Font& font,
46 OmniboxView* omnibox_view,
47 AutocompleteEditModel* edit_model,
48 views::View* location_bar)
49 : model_(new OmniboxPopupModel(this, edit_model)),
50 omnibox_view_(omnibox_view),
51 profile_(edit_model->profile()),
52 location_bar_(location_bar),
53 result_font_(font.DeriveFont(kEditFontAdjust)),
54 result_bold_font_(result_font_.DeriveFont(0, gfx::Font::BOLD)),
55 ignore_mouse_drag_(false),
56 ALLOW_THIS_IN_INITIALIZER_LIST(size_animation_(this)) {
57 // We're owned by LocationBarView.
58 set_owned_by_client();
59 // Our visibility determines whether the popup is open. Start out closed.
60 SetVisible(false);
61 // TODO(sky): replace with constant kNTPBackgroundColor.
62 set_background(views::Background::CreateSolidBackground(
63 SkColorSetRGB(0xF5, 0xF5, 0xF5)));
64 }
65
66 InlineOmniboxPopupView::~InlineOmniboxPopupView() {
67 }
68
69 void InlineOmniboxPopupView::Init() {
70 // This can't be done in the constructor as at that point we aren't
71 // necessarily our final class yet, and we may have subclasses
72 // overriding CreateResultView.
73 for (size_t i = 0; i < AutocompleteResult::kMaxMatches; ++i) {
74 OmniboxResultView* result_view =
75 CreateResultView(this, i, result_font_, result_bold_font_);
76 result_view->SetVisible(false);
77 AddChildViewAt(result_view, static_cast<int>(i));
78 }
79 }
80
81 gfx::Rect InlineOmniboxPopupView::GetPopupBounds() const {
82 if (!size_animation_.is_animating())
83 return target_bounds_;
84
85 gfx::Rect current_frame_bounds = start_bounds_;
86 int total_height_delta = target_bounds_.height() - start_bounds_.height();
87 // Round |current_height_delta| instead of truncating so we won't leave single
88 // white pixels at the bottom of the popup as long when animating very small
89 // height differences.
90 int current_height_delta = static_cast<int>(
91 size_animation_.GetCurrentValue() * total_height_delta - 0.5);
92 current_frame_bounds.set_height(
93 current_frame_bounds.height() + current_height_delta);
94 return current_frame_bounds;
95 }
96
97 void InlineOmniboxPopupView::LayoutChildren() {
98 // Make the children line up with the LocationBar.
99 gfx::Point content_origin;
100 // TODO(sky): this won't work correctly with LocationBarContainer.
101 views::View::ConvertPointToView(location_bar_, this, &content_origin);
102 int x = content_origin.x();
103 int width = location_bar_->width();
104 gfx::Rect contents_rect = GetContentsBounds();
105 int top = contents_rect.y();
106 for (int i = 0; i < child_count(); ++i) {
107 View* v = child_at(i);
108 if (v->visible()) {
109 v->SetBounds(x, top, width, v->GetPreferredSize().height());
110 top = v->bounds().bottom();
111 }
112 }
113 }
114
115 ////////////////////////////////////////////////////////////////////////////////
116 // InlineOmniboxPopupView, AutocompletePopupView overrides:
117
118 bool InlineOmniboxPopupView::IsOpen() const {
119 return visible();
120 }
121
122 void InlineOmniboxPopupView::InvalidateLine(size_t line) {
123 OmniboxResultView* result = static_cast<OmniboxResultView*>(
124 child_at(static_cast<int>(line)));
125 result->Invalidate();
126
127 if (HasMatchAt(line) && GetMatchAtIndex(line).associated_keyword.get()) {
128 result->ShowKeyword(IsSelectedIndex(line) &&
129 model_->selected_line_state() == OmniboxPopupModel::KEYWORD);
130 }
131 }
132
133 void InlineOmniboxPopupView::UpdatePopupAppearance() {
134 if (model_->result().empty()) {
135 SetVisible(false);
136 PreferredSizeChanged();
137 return;
138 }
139
140 // Update the match cached by each row, in the process of doing so make sure
141 // we have enough row views.
142 size_t child_rv_count = child_count();
143 const size_t result_size = model_->result().size();
144 for (size_t i = 0; i < result_size; ++i) {
145 OmniboxResultView* view = static_cast<OmniboxResultView*>(child_at(i));
146 view->SetMatch(GetMatchAtIndex(i));
147 view->SetVisible(true);
148 }
149 for (size_t i = result_size; i < child_rv_count; ++i)
150 child_at(i)->SetVisible(false);
151
152 gfx::Rect new_target_bounds = CalculateTargetBounds(CalculatePopupHeight());
153
154 // If we're animating and our target height changes, reset the animation.
155 // NOTE: If we just reset blindly on _every_ update, then when the user types
156 // rapidly we could get "stuck" trying repeatedly to animate shrinking by the
157 // last few pixels to get to one visible result.
158 if (new_target_bounds.height() != target_bounds_.height()) {
159 size_animation_.Reset();
160 PreferredSizeChanged();
161 }
162 target_bounds_ = new_target_bounds;
163
164 if (!visible()) {
165 SetVisible(true);
166 PreferredSizeChanged();
167 } else {
168 // Animate the popup shrinking, but don't animate growing larger since that
169 // would make the popup feel less responsive.
170 start_bounds_ = bounds();
171 if (target_bounds_.height() < start_bounds_.height())
172 size_animation_.Show();
173 else
174 start_bounds_ = target_bounds_;
175 if (GetPopupBounds().height() != bounds().height())
176 PreferredSizeChanged();
177 }
178
179 SchedulePaint();
180 }
181
182 gfx::Rect InlineOmniboxPopupView::GetTargetBounds() {
183 // Our bounds never obscure the page, so we return an empty rect.
184 return gfx::Rect();
185 }
186
187 void InlineOmniboxPopupView::PaintUpdatesNow() {
188 // TODO(beng): remove this from the interface.
189 }
190
191 void InlineOmniboxPopupView::OnDragCanceled() {
192 ignore_mouse_drag_ = true;
193 }
194
195 ////////////////////////////////////////////////////////////////////////////////
196 // InlineOmniboxPopupView, OmniboxResultViewModel implementation:
197
198 bool InlineOmniboxPopupView::IsSelectedIndex(size_t index) const {
199 return index == model_->selected_line();
200 }
201
202 bool InlineOmniboxPopupView::IsHoveredIndex(size_t index) const {
203 return index == model_->hovered_line();
204 }
205
206 const SkBitmap* InlineOmniboxPopupView::GetIconIfExtensionMatch(
207 size_t index) const {
208 if (!HasMatchAt(index))
209 return NULL;
210 return model_->GetIconIfExtensionMatch(GetMatchAtIndex(index));
211 }
212
213 ////////////////////////////////////////////////////////////////////////////////
214 // InlineOmniboxPopupView, AnimationDelegate implementation:
215
216 void InlineOmniboxPopupView::AnimationProgressed(
217 const ui::Animation* animation) {
218 // We should only be running the animation when the popup is already visible.
219 DCHECK(visible());
220 PreferredSizeChanged();
221 }
222
223 ////////////////////////////////////////////////////////////////////////////////
224 // InlineOmniboxPopupView, views::View overrides:
225
226 gfx::Size InlineOmniboxPopupView::GetPreferredSize() {
227 return GetPopupBounds().size();
228 }
229
230 void InlineOmniboxPopupView::Layout() {
231 // Size our children to the available content area.
232 LayoutChildren();
233 }
234
235 views::View* InlineOmniboxPopupView::GetEventHandlerForPoint(
236 const gfx::Point& point) {
237 return this;
238 }
239
240 bool InlineOmniboxPopupView::OnMousePressed(
241 const views::MouseEvent& event) {
242 ignore_mouse_drag_ = false; // See comment on |ignore_mouse_drag_| in header.
243 if (event.IsLeftMouseButton() || event.IsMiddleMouseButton())
244 UpdateLineEvent(event, event.IsLeftMouseButton());
245 return true;
246 }
247
248 bool InlineOmniboxPopupView::OnMouseDragged(
249 const views::MouseEvent& event) {
250 if (event.IsLeftMouseButton() || event.IsMiddleMouseButton())
251 UpdateLineEvent(event, !ignore_mouse_drag_ && event.IsLeftMouseButton());
252 return true;
253 }
254
255 void InlineOmniboxPopupView::OnMouseReleased(
256 const views::MouseEvent& event) {
257 if (ignore_mouse_drag_) {
258 OnMouseCaptureLost();
259 return;
260 }
261
262 if (event.IsOnlyMiddleMouseButton() || event.IsOnlyLeftMouseButton()) {
263 OpenSelectedLine(event, event.IsOnlyLeftMouseButton() ? CURRENT_TAB :
264 NEW_BACKGROUND_TAB);
265 }
266 }
267
268 void InlineOmniboxPopupView::OnMouseCaptureLost() {
269 ignore_mouse_drag_ = false;
270 }
271
272 void InlineOmniboxPopupView::OnMouseMoved(
273 const views::MouseEvent& event) {
274 model_->SetHoveredLine(GetIndexForPoint(event.location()));
275 }
276
277 void InlineOmniboxPopupView::OnMouseEntered(
278 const views::MouseEvent& event) {
279 model_->SetHoveredLine(GetIndexForPoint(event.location()));
Peter Kasting 2012/06/22 20:33:22 Nit: Call OnMouseMoved() instead?
280 }
281
282 void InlineOmniboxPopupView::OnMouseExited(
283 const views::MouseEvent& event) {
284 model_->SetHoveredLine(OmniboxPopupModel::kNoMatch);
285 }
286
287 ui::GestureStatus InlineOmniboxPopupView::OnGestureEvent(
288 const views::GestureEvent& event) {
289 switch (event.type()) {
290 case ui::ET_GESTURE_TAP_DOWN:
291 case ui::ET_GESTURE_SCROLL_BEGIN:
292 case ui::ET_GESTURE_SCROLL_UPDATE:
293 UpdateLineEvent(event, true);
294 break;
295 case ui::ET_GESTURE_TAP:
296 case ui::ET_GESTURE_SCROLL_END:
297 OpenSelectedLine(event, CURRENT_TAB);
298 break;
299 default:
300 return ui::GESTURE_STATUS_UNKNOWN;
301 }
302 return ui::GESTURE_STATUS_CONSUMED;
303 }
304
305 ////////////////////////////////////////////////////////////////////////////////
306 // InlineOmniboxPopupView, protected:
307
308 int InlineOmniboxPopupView::CalculatePopupHeight() {
309 DCHECK_GE(static_cast<size_t>(child_count()), model_->result().size());
310 int popup_height = 0;
311 for (size_t i = 0; i < model_->result().size(); ++i)
312 popup_height += child_at(i)->GetPreferredSize().height();
313 return popup_height;
314 }
315
316 OmniboxResultView* InlineOmniboxPopupView::CreateResultView(
317 OmniboxResultViewModel* model,
318 int model_index,
319 const gfx::Font& font,
320 const gfx::Font& bold_font) {
321 return new OmniboxResultView(model, model_index, font, bold_font);
322 }
323
324 ////////////////////////////////////////////////////////////////////////////////
325 // InlineOmniboxPopupView, private:
326
327 bool InlineOmniboxPopupView::HasMatchAt(size_t index) const {
328 return index < model_->result().size();
329 }
330
331 const AutocompleteMatch& InlineOmniboxPopupView::GetMatchAtIndex(
332 size_t index) const {
333 return model_->result().match_at(index);
334 }
335
336 void InlineOmniboxPopupView::MakeContentsPath(
337 gfx::Path* path,
338 const gfx::Rect& bounding_rect) {
339 SkRect rect;
340 rect.set(SkIntToScalar(bounding_rect.x()),
341 SkIntToScalar(bounding_rect.y()),
342 SkIntToScalar(bounding_rect.right()),
343 SkIntToScalar(bounding_rect.bottom()));
344
345 SkScalar radius = SkIntToScalar(views::BubbleBorder::GetCornerRadius());
346 path->addRoundRect(rect, radius, radius);
347 }
348
349 void InlineOmniboxPopupView::OpenIndex(size_t index,
350 WindowOpenDisposition disposition) {
351 if (!HasMatchAt(index))
352 return;
353
354 // OpenMatch() may close the popup, which will clear the result set and, by
355 // extension, |match| and its contents. So copy the relevant match out to
356 // make sure it stays alive until the call completes.
357 AutocompleteMatch match = model_->result().match_at(index);
358 omnibox_view_->OpenMatch(match, disposition, GURL(), index);
359 }
360
361 size_t InlineOmniboxPopupView::GetIndexForPoint(const gfx::Point& point) {
362 if (!HitTest(point))
363 return OmniboxPopupModel::kNoMatch;
364
365 int nb_match = model_->result().size();
366 DCHECK(nb_match <= child_count());
367 for (int i = 0; i < nb_match; ++i) {
368 views::View* child = child_at(i);
369 gfx::Point point_in_child_coords(point);
370 View::ConvertPointToView(this, child, &point_in_child_coords);
371 if (child->HitTest(point_in_child_coords))
372 return i;
373 }
374 return OmniboxPopupModel::kNoMatch;
375 }
376
377 gfx::Rect InlineOmniboxPopupView::CalculateTargetBounds(int h) {
378 return gfx::Rect(0, 0, 1, h);
379 }
380
381 void InlineOmniboxPopupView::UpdateLineEvent(
382 const views::LocatedEvent& event,
383 bool should_set_selected_line) {
384 size_t index = GetIndexForPoint(event.location());
385 model_->SetHoveredLine(index);
386 if (HasMatchAt(index) && should_set_selected_line)
387 model_->SetSelectedLine(index, false, false);
388 }
389
390 void InlineOmniboxPopupView::OpenSelectedLine(
391 const views::LocatedEvent& event,
392 WindowOpenDisposition disposition) {
393 size_t index = GetIndexForPoint(event.location());
394 OpenIndex(index, disposition);
395 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698