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

Side by Side Diff: chrome/browser/views/autocomplete/autocomplete_popup_win.cc

Issue 79032: Split out the contents view into its own header. rename it to AutocompletePop... (Closed) Base URL: svn://chrome-svn.corp.google.com/chrome/trunk/src/
Patch Set: '' Created 11 years, 8 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
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in the 2 // source code is governed by a BSD-style license that can be found in the
3 // LICENSE file. 3 // LICENSE file.
4 4
5 #include "chrome/browser/views/autocomplete/autocomplete_popup_win.h" 5 #include "chrome/browser/views/autocomplete/autocomplete_popup_win.h"
6 6
7 #include <dwmapi.h>
8
9 #include "chrome/browser/autocomplete/autocomplete_edit_view_win.h" 7 #include "chrome/browser/autocomplete/autocomplete_edit_view_win.h"
10 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" 8 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
11 #include "chrome/common/gfx/chrome_canvas.h" 9 #include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h"
12 #include "chrome/common/gfx/color_utils.h"
13 #include "chrome/common/gfx/insets.h" 10 #include "chrome/common/gfx/insets.h"
14 #include "chrome/common/gfx/path.h"
15 #include "chrome/common/resource_bundle.h"
16 #include "chrome/common/win_util.h" 11 #include "chrome/common/win_util.h"
17 #include "grit/theme_resources.h"
18 #include "skia/include/SkShader.h"
19
20 // The stroke color around the popup border.
21 static const SkColor kEdgeColor = SkColorSetRGB(183, 195, 219);
22 static const int kPopupTransparency = 235;
23 static const int kHoverRowAlpha = 0x40;
24
25 // TODO(beng): documentation, finalize
26 class AutocompleteResultViewModel {
27 public:
28 virtual bool IsSelectedIndex(size_t index) = 0;
29
30 virtual AutocompleteMatch::Type GetResultTypeAtIndex(size_t index) = 0;
31
32 virtual void OpenIndex(size_t index, WindowOpenDisposition disposition) = 0;
33
34 virtual void SetHoveredLine(size_t index) = 0;
35 virtual void SetSelectedLine(size_t index, bool revert_to_default) = 0;
36 };
37
38 class AutocompleteResultView : public views::View {
39 public:
40 AutocompleteResultView(AutocompleteResultViewModel* model, int model_index);
41 virtual ~AutocompleteResultView();
42
43 // Overridden from views::View:
44 virtual void Paint(ChromeCanvas* canvas);
45 virtual gfx::Size GetPreferredSize();
46 virtual void OnMouseEntered(const views::MouseEvent& event);
47 virtual void OnMouseMoved(const views::MouseEvent& event);
48 virtual void OnMouseExited(const views::MouseEvent& event);
49 virtual bool OnMousePressed(const views::MouseEvent& event);
50 virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
51 virtual bool OnMouseDragged(const views::MouseEvent& event);
52
53 private:
54 // Paint the result view in different ways.
55 void PaintAsSearchDefault(ChromeCanvas* canvas);
56 void PaintAsURLSuggestion(ChromeCanvas* canvas);
57 void PaintAsQuerySuggestion(ChromeCanvas* canvas);
58 void PaintAsMoreRow(ChromeCanvas* canvas);
59
60 // Get colors for row backgrounds and text for different row states.
61 SkColor GetHighlightRowColor() const;
62 SkColor GetHighlightTextColor() const;
63 SkColor GetHoverRowColor() const;
64 SkColor GetTextColor() const;
65
66 // This row's model and model index.
67 AutocompleteResultViewModel* model_;
68 size_t model_index_;
69
70 // True if the mouse is over this row.
71 bool hot_;
72
73 DISALLOW_COPY_AND_ASSIGN(AutocompleteResultView);
74 };
75
76 AutocompleteResultView::AutocompleteResultView(
77 AutocompleteResultViewModel* model,
78 int model_index)
79 : model_(model),
80 model_index_(model_index),
81 hot_(false) {
82 }
83
84 AutocompleteResultView::~AutocompleteResultView() {
85 }
86
87 void AutocompleteResultView::Paint(ChromeCanvas* canvas) {
88 // Paint the row background if any.
89 if (model_->IsSelectedIndex(model_index_))
90 canvas->FillRectInt(GetHighlightRowColor(), 0, 0, width(), height());
91 else if (hot_)
92 canvas->FillRectInt(GetHoverRowColor(), 0, 0, width(), height());
93 }
94
95 gfx::Size AutocompleteResultView::GetPreferredSize() {
96 return gfx::Size(0, 30);
97 }
98
99 void AutocompleteResultView::OnMouseEntered(const views::MouseEvent& event) {
100 hot_ = true;
101 SchedulePaint();
102 }
103
104 void AutocompleteResultView::OnMouseMoved(const views::MouseEvent& event) {
105 if (!hot_) {
106 hot_ = true;
107 SchedulePaint();
108 }
109 }
110
111 void AutocompleteResultView::OnMouseExited(const views::MouseEvent& event) {
112 hot_ = false;
113 SchedulePaint();
114 }
115
116 bool AutocompleteResultView::OnMousePressed(const views::MouseEvent& event) {
117 if (event.IsOnlyLeftMouseButton()) {
118 model_->SetHoveredLine(model_index_);
119 model_->SetSelectedLine(model_index_, false);
120 } else if (event.IsOnlyMiddleMouseButton()) {
121 model_->SetHoveredLine(model_index_);
122 }
123 return true;
124 }
125
126 void AutocompleteResultView::OnMouseReleased(const views::MouseEvent& event,
127 bool canceled) {
128 if (canceled)
129 return;
130 if (event.IsOnlyMiddleMouseButton())
131 model_->OpenIndex(model_index_, NEW_BACKGROUND_TAB);
132 else if (event.IsOnlyLeftMouseButton())
133 model_->OpenIndex(model_index_, CURRENT_TAB);
134 }
135
136 bool AutocompleteResultView::OnMouseDragged(const views::MouseEvent& event) {
137 // TODO(beng): move all message handling into the contents view and override
138 // GetViewForPoint.
139 return false;
140 }
141
142 void AutocompleteResultView::PaintAsSearchDefault(ChromeCanvas* canvas) {
143
144 }
145
146 void AutocompleteResultView::PaintAsURLSuggestion(ChromeCanvas* canvas) {
147
148 }
149
150 void AutocompleteResultView::PaintAsQuerySuggestion(ChromeCanvas* canvas) {
151
152 }
153
154 void AutocompleteResultView::PaintAsMoreRow(ChromeCanvas* canvas) {
155
156 }
157
158 SkColor AutocompleteResultView::GetHighlightRowColor() const {
159 return color_utils::GetSysSkColor(COLOR_HIGHLIGHT);
160 }
161
162 SkColor AutocompleteResultView::GetHighlightTextColor() const {
163 return color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT);
164 }
165
166 SkColor AutocompleteResultView::GetHoverRowColor() const {
167 COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
168 return SkColorSetARGB(kHoverRowAlpha, GetRValue(color), GetGValue(color),
169 GetBValue(color));
170 }
171
172 SkColor AutocompleteResultView::GetTextColor() const {
173 return color_utils::GetSysSkColor(COLOR_WINDOWTEXT);
174 }
175
176 class PopupBorder : public views::Border {
177 public:
178 PopupBorder() {
179 InitClass();
180 }
181 virtual ~PopupBorder() {}
182
183 // Returns the border radius of the edge of the popup.
184 static int GetBorderRadius() {
185 InitClass();
186 return dropshadow_topleft_->width() - dropshadow_left_->width() - 1;
187 }
188
189 // Overridden from views::Border:
190 virtual void Paint(const views::View& view, ChromeCanvas* canvas) const;
191 virtual void GetInsets(gfx::Insets* insets) const;
192
193 private:
194 // Border graphics.
195 static SkBitmap* dropshadow_left_;
196 static SkBitmap* dropshadow_topleft_;
197 static SkBitmap* dropshadow_top_;
198 static SkBitmap* dropshadow_topright_;
199 static SkBitmap* dropshadow_right_;
200 static SkBitmap* dropshadow_bottomright_;
201 static SkBitmap* dropshadow_bottom_;
202 static SkBitmap* dropshadow_bottomleft_;
203
204 static void InitClass();
205
206 DISALLOW_COPY_AND_ASSIGN(PopupBorder);
207 };
208
209 // static
210 SkBitmap* PopupBorder::dropshadow_left_ = NULL;
211 SkBitmap* PopupBorder::dropshadow_topleft_ = NULL;
212 SkBitmap* PopupBorder::dropshadow_top_ = NULL;
213 SkBitmap* PopupBorder::dropshadow_topright_ = NULL;
214 SkBitmap* PopupBorder::dropshadow_right_ = NULL;
215 SkBitmap* PopupBorder::dropshadow_bottomright_ = NULL;
216 SkBitmap* PopupBorder::dropshadow_bottom_ = NULL;
217 SkBitmap* PopupBorder::dropshadow_bottomleft_ = NULL;
218
219 void PopupBorder::Paint(const views::View& view, ChromeCanvas* canvas) const {
220 int ds_tl_width = dropshadow_topleft_->width();
221 int ds_tl_height = dropshadow_topleft_->height();
222 int ds_tr_width = dropshadow_topright_->width();
223 int ds_tr_height = dropshadow_topright_->height();
224 int ds_br_width = dropshadow_bottomright_->width();
225 int ds_br_height = dropshadow_bottomright_->height();
226 int ds_bl_width = dropshadow_bottomleft_->width();
227 int ds_bl_height = dropshadow_bottomleft_->height();
228
229 canvas->DrawBitmapInt(*dropshadow_topleft_, 0, 0);
230 canvas->TileImageInt(*dropshadow_top_, ds_tl_width, 0,
231 view.width() - ds_tr_width - ds_tl_width,
232 dropshadow_top_->height());
233 canvas->DrawBitmapInt(*dropshadow_topright_, view.width() - ds_tr_width, 0);
234 canvas->TileImageInt(*dropshadow_right_,
235 view.width() - dropshadow_right_->width(),
236 ds_tr_height, dropshadow_right_->width(),
237 view.height() - ds_tr_height - ds_br_height);
238 canvas->DrawBitmapInt(*dropshadow_bottomright_, view.width() - ds_br_width,
239 view.height() - ds_br_height);
240 canvas->TileImageInt(*dropshadow_bottom_, ds_bl_width,
241 view.height() - dropshadow_bottom_->height(),
242 view.width() - ds_bl_width - ds_br_width,
243 dropshadow_bottom_->height());
244 canvas->DrawBitmapInt(*dropshadow_bottomleft_, 0,
245 view.height() - dropshadow_bottomleft_->height());
246 canvas->TileImageInt(*dropshadow_left_, 0, ds_tl_height,
247 dropshadow_left_->width(),
248 view.height() - ds_tl_height - ds_bl_height);
249 }
250
251 void PopupBorder::GetInsets(gfx::Insets* insets) const {
252 // The left, right and bottom edge image sizes define our insets. The corner
253 // images don't determine this because they can extend in both directions.
254 insets->Set(dropshadow_top_->height(), dropshadow_left_->width(),
255 dropshadow_bottom_->height(), dropshadow_right_->width());
256 }
257
258 void PopupBorder::InitClass() {
259 static bool initialized = false;
260 if (!initialized) {
261 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
262 dropshadow_left_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_L);
263 dropshadow_topleft_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_TL);
264 dropshadow_top_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_T);
265 dropshadow_topright_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_TR);
266 dropshadow_right_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_R);
267 dropshadow_bottomright_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_BR);
268 dropshadow_bottom_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_B);
269 dropshadow_bottomleft_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_BL);
270 initialized = true;
271 }
272 }
273
274 class AutocompletePopupViewContents : public views::View,
275 public AutocompleteResultViewModel {
276 public:
277 explicit AutocompletePopupViewContents(AutocompletePopupWin* popup)
278 : popup_(popup) {
279 set_border(new PopupBorder);
280 }
281 virtual ~AutocompletePopupViewContents() {}
282
283 // Update the presentation with the latest result.
284 void SetAutocompleteResult(const AutocompleteResult& result);
285
286 // Schedule a repaint for the specified row.
287 void InvalidateLine(int index);
288
289 // Overridden from AutocompleteResultViewModel:
290 virtual bool IsSelectedIndex(size_t index);
291 virtual AutocompleteMatch::Type GetResultTypeAtIndex(size_t index);
292 virtual void OpenIndex(size_t index, WindowOpenDisposition disposition);
293 virtual void SetHoveredLine(size_t index);
294 virtual void SetSelectedLine(size_t index, bool revert_to_default);
295
296 // Overridden from views::View:
297 virtual void PaintChildren(ChromeCanvas* canvas);
298 virtual void Layout();
299
300 private:
301 // Fill a path for the contents' roundrect. |bounding_rect| is the rect that
302 // bounds the path.
303 void MakeContentsPath(gfx::Path* path, const gfx::Rect& bounding_rect);
304
305 // Updates the window's blur region for the current size.
306 void UpdateBlurRegion();
307
308 // Makes the contents of the canvas slightly transparent.
309 void MakeCanvasTransparent(ChromeCanvas* canvas);
310
311 AutocompletePopupWin* popup_;
312
313 DISALLOW_COPY_AND_ASSIGN(AutocompletePopupViewContents);
314 };
315
316 void AutocompletePopupViewContents::SetAutocompleteResult(
317 const AutocompleteResult& result) {
318 RemoveAllChildViews(true);
319 for (size_t i = 0; i < result.size(); ++i) {
320 AutocompleteMatch match = result.match_at(i);
321 AutocompleteResultView* result = new AutocompleteResultView(this, i);
322 AddChildView(result);
323 }
324 Layout();
325 }
326
327 void AutocompletePopupViewContents::InvalidateLine(int index) {
328 GetChildViewAt(index)->SchedulePaint();
329 }
330
331 bool AutocompletePopupViewContents::IsSelectedIndex(size_t index) {
332 return index == popup_->GetModel()->selected_line();
333 }
334
335 AutocompleteMatch::Type AutocompletePopupViewContents::GetResultTypeAtIndex(
336 size_t index) {
337 return popup_->GetModel()->result().match_at(index).type;
338 }
339
340 void AutocompletePopupViewContents::OpenIndex(
341 size_t index,
342 WindowOpenDisposition disposition) {
343 popup_->OpenIndex(index, disposition);
344 }
345
346 void AutocompletePopupViewContents::SetHoveredLine(size_t index) {
347 popup_->SetHoveredLine(index);
348 }
349
350 void AutocompletePopupViewContents::SetSelectedLine(size_t index,
351 bool revert_to_default) {
352 popup_->SetSelectedLine(index, revert_to_default);
353 }
354
355 void AutocompletePopupViewContents::PaintChildren(ChromeCanvas* canvas) {
356 // We paint our children in an unconventional way.
357 //
358 // Because the border of this view creates an anti-aliased round-rect region
359 // for the contents, we need to render our rectangular result child views into
360 // this round rect region. We can't use a simple clip because clipping is
361 // 1-bit and we get nasty jagged edges.
362 //
363 // Instead, we paint all our children into a second canvas and use that as a
364 // shader to fill a path representing the round-rect clipping region. This
365 // yields a nice anti-aliased edge.
366 gfx::Rect contents_rect = GetLocalBounds(false);
367 ChromeCanvas contents_canvas(contents_rect.width(), contents_rect.height(),
368 true);
369 contents_canvas.FillRectInt(color_utils::GetSysSkColor(COLOR_WINDOW), 0, 0,
370 contents_rect.width(), contents_rect.height());
371 // We want the contents background to be slightly transparent so we can see
372 // the blurry glass effect on DWM systems behind.
373 MakeCanvasTransparent(&contents_canvas);
374 View::PaintChildren(&contents_canvas);
375
376 // Now paint the contents of the contents canvas into the actual canvas.
377 SkPaint paint;
378 paint.setAntiAlias(true);
379
380 SkShader* shader = SkShader::CreateBitmapShader(
381 contents_canvas.getDevice()->accessBitmap(false),
382 SkShader::kClamp_TileMode,
383 SkShader::kClamp_TileMode);
384 paint.setShader(shader);
385 shader->unref();
386
387 gfx::Path path;
388 MakeContentsPath(&path, contents_rect);
389 canvas->drawPath(path, paint);
390 }
391
392 void AutocompletePopupViewContents::Layout() {
393 UpdateBlurRegion();
394
395 // Size our children to the available content area.
396 gfx::Rect contents_rect = GetLocalBounds(false);
397 int child_count = GetChildViewCount();
398 int top = contents_rect.y();
399 for (int i = 0; i < child_count; ++i) {
400 View* v = GetChildViewAt(i);
401 v->SetBounds(contents_rect.x(), top, contents_rect.width(),
402 v->GetPreferredSize().height());
403 top = v->bounds().bottom();
404 }
405
406 // We need to manually schedule a paint here since we are a layered window and
407 // won't implicitly require painting until we ask for one.
408 SchedulePaint();
409 }
410
411 void AutocompletePopupViewContents::MakeContentsPath(
412 gfx::Path* path,
413 const gfx::Rect& bounding_rect) {
414 SkRect rect;
415 rect.set(SkIntToScalar(bounding_rect.x()),
416 SkIntToScalar(bounding_rect.y()),
417 SkIntToScalar(bounding_rect.right()),
418 SkIntToScalar(bounding_rect.bottom()));
419
420 SkScalar radius = SkIntToScalar(PopupBorder::GetBorderRadius());
421 path->addRoundRect(rect, radius, radius);
422 }
423
424 void AutocompletePopupViewContents::UpdateBlurRegion() {
425 // Provide a blurred background effect within the contents region of the
426 // popup.
427 DWM_BLURBEHIND bb = {0};
428 bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
429 bb.fEnable = true;
430
431 // Translate the contents rect into widget coordinates, since that's what
432 // DwmEnableBlurBehindWindow expects a region in.
433 gfx::Rect contents_rect = GetLocalBounds(false);
434 gfx::Point origin(contents_rect.origin());
435 views::View::ConvertPointToWidget(this, &origin);
436 contents_rect.set_origin(origin);
437
438 gfx::Path contents_path;
439 MakeContentsPath(&contents_path, contents_rect);
440 ScopedGDIObject<HRGN> popup_region;
441 popup_region.Set(contents_path.CreateHRGN());
442 bb.hRgnBlur = popup_region.Get();
443 DwmEnableBlurBehindWindow(GetWidget()->GetNativeView(), &bb);
444 }
445
446 void AutocompletePopupViewContents::MakeCanvasTransparent(
447 ChromeCanvas* canvas) {
448 // Allow the window blur effect to show through the popup background.
449 SkPaint paint;
450 paint.setColor(SkColorSetARGB(kPopupTransparency, 255, 255, 255));
451 paint.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode);
452 paint.setStyle(SkPaint::kFill_Style);
453 canvas->FillRectInt(0, 0, canvas->getDevice()->width(),
454 canvas->getDevice()->height(), paint);
455 }
456 12
457 //////////////////////////////////////////////////////////////////////////////// 13 ////////////////////////////////////////////////////////////////////////////////
458 // AutocompletePopupWin, public: 14 // AutocompletePopupWin, public:
459 15
460 AutocompletePopupWin::AutocompletePopupWin( 16 AutocompletePopupWin::AutocompletePopupWin(
461 const ChromeFont& font, 17 const ChromeFont& font,
462 AutocompleteEditViewWin* edit_view, 18 AutocompleteEditViewWin* edit_view,
463 AutocompleteEditModel* edit_model, 19 AutocompleteEditModel* edit_model,
464 Profile* profile, 20 Profile* profile,
465 AutocompletePopupPositioner* popup_positioner) 21 AutocompletePopupPositioner* popup_positioner)
466 : model_(new AutocompletePopupModel(this, edit_model, profile)), 22 : model_(new AutocompletePopupModel(this, edit_model, profile)),
467 edit_view_(edit_view), 23 edit_view_(edit_view),
468 popup_positioner_(popup_positioner), 24 popup_positioner_(popup_positioner),
469 contents_(new AutocompletePopupViewContents(this)) { 25 contents_(new AutocompletePopupContentsView(this)) {
470 set_delete_on_destroy(false); 26 set_delete_on_destroy(false);
471 set_window_style(WS_POPUP | WS_CLIPCHILDREN); 27 set_window_style(WS_POPUP | WS_CLIPCHILDREN);
472 set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED); 28 set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED);
473 } 29 }
474 30
475 AutocompletePopupWin::~AutocompletePopupWin() { 31 AutocompletePopupWin::~AutocompletePopupWin() {
476 } 32 }
477 33
478 //////////////////////////////////////////////////////////////////////////////// 34 ////////////////////////////////////////////////////////////////////////////////
479 // AutocompletePopupWin, AutocompletePopupView overrides: 35 // AutocompletePopupWin, AutocompletePopupView overrides:
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 is_keyword_hint ? std::wstring() : keyword); 124 is_keyword_hint ? std::wstring() : keyword);
569 } 125 }
570 126
571 void AutocompletePopupWin::SetHoveredLine(int index) { 127 void AutocompletePopupWin::SetHoveredLine(int index) {
572 model_->SetHoveredLine(index); 128 model_->SetHoveredLine(index);
573 } 129 }
574 130
575 void AutocompletePopupWin::SetSelectedLine(int index, bool revert_to_default) { 131 void AutocompletePopupWin::SetSelectedLine(int index, bool revert_to_default) {
576 model_->SetSelectedLine(index, revert_to_default); 132 model_->SetSelectedLine(index, revert_to_default);
577 } 133 }
OLDNEW
« no previous file with comments | « chrome/browser/views/autocomplete/autocomplete_popup_win.h ('k') | chrome/browser/views/browser_views.vcproj » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698