Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / views / link_disambiguation / link_disambiguation_popup.cc
blob7186ab3ec3d004cb29fbd236bfb4ab2b3a00f01e
1 // Copyright (c) 2014 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.
5 #include "chrome/browser/ui/views/link_disambiguation/link_disambiguation_popup.h"
7 #include "ui/aura/client/screen_position_client.h"
8 #include "ui/events/event.h"
9 #include "ui/events/event_processor.h"
10 #include "ui/events/event_utils.h"
11 #include "ui/events/gesture_event_details.h"
12 #include "ui/gfx/display.h"
13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/image/image_skia.h"
15 #include "ui/gfx/screen.h"
16 #include "ui/views/bubble/bubble_delegate.h"
17 #include "ui/views/controls/image_view.h"
19 class LinkDisambiguationPopup::ZoomBubbleView
20 : public views::BubbleDelegateView {
21 public:
22 ZoomBubbleView(views::Widget* top_level_widget,
23 const gfx::Rect& target_rect,
24 const gfx::ImageSkia* zoomed_skia_image,
25 LinkDisambiguationPopup* popup,
26 const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
27 const base::Callback<void(ui::MouseEvent*)>& mouse_cb);
29 void Close();
31 private:
32 // views::View overrides
33 gfx::Size GetPreferredSize() const override;
34 void OnGestureEvent(ui::GestureEvent* event) override;
35 void OnMouseEvent(ui::MouseEvent* event) override;
37 // WidgetObserver overrides
38 void OnWidgetClosing(views::Widget* widget) override;
40 const float scale_;
41 const base::Callback<void(ui::GestureEvent*)> gesture_cb_;
42 const base::Callback<void(ui::MouseEvent*)> mouse_cb_;
43 LinkDisambiguationPopup* popup_;
44 const gfx::Rect target_rect_;
46 DISALLOW_COPY_AND_ASSIGN(ZoomBubbleView);
49 LinkDisambiguationPopup::ZoomBubbleView::ZoomBubbleView(
50 views::Widget* top_level_widget,
51 const gfx::Rect& target_rect,
52 const gfx::ImageSkia* zoomed_skia_image,
53 LinkDisambiguationPopup* popup,
54 const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
55 const base::Callback<void(ui::MouseEvent*)>& mouse_cb)
56 : BubbleDelegateView(
57 top_level_widget ? top_level_widget->GetContentsView() : nullptr,
58 views::BubbleBorder::FLOAT),
59 scale_(static_cast<float>(zoomed_skia_image->width()) /
60 static_cast<float>(target_rect.width())),
61 gesture_cb_(gesture_cb),
62 mouse_cb_(mouse_cb),
63 popup_(popup),
64 target_rect_(target_rect) {
65 views::ImageView* image_view = new views::ImageView();
66 image_view->SetBounds(
67 0, 0, zoomed_skia_image->width(), zoomed_skia_image->height());
68 image_view->SetImage(zoomed_skia_image);
70 AddChildView(image_view);
72 views::BubbleDelegateView::CreateBubble(this);
75 void LinkDisambiguationPopup::ZoomBubbleView::Close() {
76 if (GetWidget())
77 GetWidget()->Close();
80 gfx::Size LinkDisambiguationPopup::ZoomBubbleView::GetPreferredSize() const {
81 return target_rect_.size();
84 void LinkDisambiguationPopup::ZoomBubbleView::OnMouseEvent(
85 ui::MouseEvent* event) {
86 // Transform mouse event back to coordinate system of the web content window
87 // before providing to the callback.
88 gfx::PointF xform_location(
89 (event->location().x() / scale_) + target_rect_.x(),
90 (event->location().y() / scale_) + target_rect_.y());
91 ui::MouseEvent xform_event(event->type(), xform_location, xform_location,
92 ui::EventTimeForNow(), event->flags(),
93 event->changed_button_flags());
94 mouse_cb_.Run(&xform_event);
95 event->SetHandled();
97 // If user completed a click we can close the window.
98 if (event->type() == ui::EventType::ET_MOUSE_RELEASED)
99 Close();
102 void LinkDisambiguationPopup::ZoomBubbleView::OnGestureEvent(
103 ui::GestureEvent* event) {
104 // If we receive gesture events that are outside of our bounds we close
105 // ourselves, as perhaps the user has decided on a different part of the page.
106 if (event->location().x() > bounds().width() ||
107 event->location().y() > bounds().height()) {
108 Close();
109 return;
112 // Scale the gesture event back to the size of the original |target_rect_|,
113 // and then offset it to be relative to that |target_rect_| before sending
114 // it back to the callback.
115 gfx::PointF xform_location(
116 (event->location().x() / scale_) + target_rect_.x(),
117 (event->location().y() / scale_) + target_rect_.y());
118 ui::GestureEventDetails xform_details(event->details());
119 xform_details.set_bounding_box(gfx::RectF(
120 (event->details().bounding_box().x() / scale_) + target_rect_.x(),
121 (event->details().bounding_box().y() / scale_) + target_rect_.y(),
122 event->details().bounding_box().width() / scale_,
123 event->details().bounding_box().height() / scale_));
124 ui::GestureEvent xform_event(xform_location.x(),
125 xform_location.y(),
126 event->flags(),
127 event->time_stamp(),
128 xform_details);
129 gesture_cb_.Run(&xform_event);
130 event->SetHandled();
132 // If we completed a tap we close ourselves, as the web content will navigate
133 // if the user hit a link.
134 if (event->type() == ui::EventType::ET_GESTURE_TAP)
135 Close();
138 void LinkDisambiguationPopup::ZoomBubbleView::OnWidgetClosing(
139 views::Widget* widget) {
140 popup_->InvalidateBubbleView();
143 LinkDisambiguationPopup::LinkDisambiguationPopup()
144 : content_(NULL),
145 view_(NULL) {
148 LinkDisambiguationPopup::~LinkDisambiguationPopup() {
149 Close();
152 void LinkDisambiguationPopup::Show(
153 views::Widget* top_level_widget,
154 const SkBitmap& zoomed_bitmap,
155 const gfx::Rect& target_rect,
156 const gfx::NativeView content,
157 const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
158 const base::Callback<void(ui::MouseEvent*)>& mouse_cb) {
159 content_ = content;
161 view_ = new ZoomBubbleView(
162 top_level_widget,
163 target_rect,
164 gfx::Image::CreateFrom1xBitmap(zoomed_bitmap).ToImageSkia(),
165 this,
166 gesture_cb,
167 mouse_cb);
169 // Center the zoomed bubble over the target rectangle, constrained to the
170 // work area in the current display. Since |target_rect| is provided in
171 // |content_| coordinate system, we must convert it into Screen coordinates
172 // for correct window positioning.
173 aura::client::ScreenPositionClient* screen_position_client =
174 aura::client::GetScreenPositionClient(content_->GetRootWindow());
175 gfx::Point target_screen(target_rect.x() + (target_rect.width() / 2),
176 target_rect.y() + (target_rect.height() / 2));
177 if (screen_position_client)
178 screen_position_client->ConvertPointToScreen(content_, &target_screen);
179 gfx::Rect window_bounds(
180 target_screen.x() - (zoomed_bitmap.width() / 2),
181 target_screen.y() - (zoomed_bitmap.height() / 2),
182 zoomed_bitmap.width(),
183 zoomed_bitmap.height());
184 const gfx::Display display =
185 gfx::Screen::GetScreenFor(content)->GetDisplayNearestWindow(content);
186 window_bounds.AdjustToFit(display.work_area());
187 view_->GetWidget()->SetBounds(window_bounds);
188 view_->GetWidget()->Show();
191 void LinkDisambiguationPopup::Close() {
192 if (view_) {
193 view_->Close();
194 view_ = NULL;
198 void LinkDisambiguationPopup::InvalidateBubbleView() {
199 view_ = NULL;