OLD | NEW |
| (Empty) |
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 "ash/common/drag_drop/drag_image_view.h" | |
6 | |
7 #include <memory> | |
8 | |
9 #include "ash/common/wm_window.h" | |
10 #include "ash/public/cpp/shell_window_ids.h" | |
11 #include "ash/root_window_controller.h" | |
12 #include "skia/ext/image_operations.h" | |
13 #include "ui/base/resource/resource_bundle.h" | |
14 #include "ui/display/display.h" | |
15 #include "ui/gfx/canvas.h" | |
16 #include "ui/resources/grit/ui_resources.h" | |
17 #include "ui/views/widget/widget.h" | |
18 | |
19 namespace ash { | |
20 namespace { | |
21 using views::Widget; | |
22 | |
23 std::unique_ptr<Widget> CreateDragWidget(WmWindow* root_window) { | |
24 std::unique_ptr<Widget> drag_widget(new Widget); | |
25 Widget::InitParams params; | |
26 params.type = Widget::InitParams::TYPE_TOOLTIP; | |
27 params.name = "DragWidget"; | |
28 params.keep_on_top = true; | |
29 params.accept_events = false; | |
30 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
31 params.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE; | |
32 params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; | |
33 root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( | |
34 drag_widget.get(), kShellWindowId_DragImageAndTooltipContainer, ¶ms); | |
35 drag_widget->Init(params); | |
36 drag_widget->SetOpacity(1.f); | |
37 return drag_widget; | |
38 } | |
39 | |
40 } // namespace | |
41 | |
42 DragImageView::DragImageView(WmWindow* root_window, | |
43 ui::DragDropTypes::DragEventSource event_source) | |
44 : drag_event_source_(event_source), | |
45 touch_drag_operation_(ui::DragDropTypes::DRAG_NONE) { | |
46 DCHECK(root_window); | |
47 widget_ = CreateDragWidget(root_window); | |
48 widget_->SetContentsView(this); | |
49 widget_->SetAlwaysOnTop(true); | |
50 | |
51 // We are owned by the DragDropController. | |
52 set_owned_by_client(); | |
53 } | |
54 | |
55 DragImageView::~DragImageView() { | |
56 widget_->Hide(); | |
57 } | |
58 | |
59 void DragImageView::SetBoundsInScreen(const gfx::Rect& bounds) { | |
60 drag_image_size_ = bounds.size(); | |
61 widget_->SetBounds(bounds); | |
62 } | |
63 | |
64 void DragImageView::SetScreenPosition(const gfx::Point& position) { | |
65 widget_->SetBounds( | |
66 gfx::Rect(position, widget_->GetWindowBoundsInScreen().size())); | |
67 } | |
68 | |
69 gfx::Rect DragImageView::GetBoundsInScreen() const { | |
70 return widget_->GetWindowBoundsInScreen(); | |
71 } | |
72 | |
73 void DragImageView::SetWidgetVisible(bool visible) { | |
74 if (visible != widget_->IsVisible()) { | |
75 if (visible) | |
76 widget_->Show(); | |
77 else | |
78 widget_->Hide(); | |
79 } | |
80 } | |
81 | |
82 void DragImageView::SetTouchDragOperationHintOff() { | |
83 // Simply set the drag type to non-touch so that no hint is drawn. | |
84 drag_event_source_ = ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE; | |
85 | |
86 // This disables the drag hint image. This should reduce the widget size if | |
87 // the drag image is smaller than the drag hint image, so we set new bounds. | |
88 gfx::Rect new_bounds = GetBoundsInScreen(); | |
89 new_bounds.set_size(drag_image_size_); | |
90 SetBoundsInScreen(new_bounds); | |
91 SchedulePaint(); | |
92 } | |
93 | |
94 void DragImageView::SetTouchDragOperation(int operation) { | |
95 if (touch_drag_operation_ == operation) | |
96 return; | |
97 touch_drag_operation_ = operation; | |
98 SchedulePaint(); | |
99 } | |
100 | |
101 void DragImageView::SetTouchDragOperationHintPosition( | |
102 const gfx::Point& position) { | |
103 if (touch_drag_operation_indicator_position_ == position) | |
104 return; | |
105 touch_drag_operation_indicator_position_ = position; | |
106 SchedulePaint(); | |
107 } | |
108 | |
109 void DragImageView::SetOpacity(float visibility) { | |
110 DCHECK_GE(visibility, 0.0f); | |
111 DCHECK_LE(visibility, 1.0f); | |
112 widget_->SetOpacity(visibility); | |
113 } | |
114 | |
115 void DragImageView::OnPaint(gfx::Canvas* canvas) { | |
116 if (GetImage().isNull()) | |
117 return; | |
118 | |
119 // |drag_image_size_| is in DIP. | |
120 // ImageSkia::size() also returns the size in DIP. | |
121 if (GetImage().size() == drag_image_size_) { | |
122 canvas->DrawImageInt(GetImage(), 0, 0); | |
123 } else { | |
124 WmWindow* window = WmWindow::Get(widget_->GetNativeWindow()); | |
125 const float device_scale = | |
126 window->GetDisplayNearestWindow().device_scale_factor(); | |
127 // The drag image already has device scale factor applied. But | |
128 // |drag_image_size_| is in DIP units. | |
129 gfx::Size drag_image_size_pixels = | |
130 gfx::ScaleToRoundedSize(drag_image_size_, device_scale); | |
131 gfx::ImageSkiaRep image_rep = GetImage().GetRepresentation(device_scale); | |
132 if (image_rep.is_null()) | |
133 return; | |
134 SkBitmap scaled = skia::ImageOperations::Resize( | |
135 image_rep.sk_bitmap(), skia::ImageOperations::RESIZE_LANCZOS3, | |
136 drag_image_size_pixels.width(), drag_image_size_pixels.height()); | |
137 gfx::ImageSkia image_skia(gfx::ImageSkiaRep(scaled, device_scale)); | |
138 canvas->DrawImageInt(image_skia, 0, 0); | |
139 } | |
140 | |
141 gfx::Image* drag_hint = DragHint(); | |
142 if (!ShouldDrawDragHint() || drag_hint->IsEmpty()) | |
143 return; | |
144 | |
145 // Make sure drag hint image is positioned within the widget. | |
146 gfx::Size drag_hint_size = drag_hint->Size(); | |
147 gfx::Point drag_hint_position = touch_drag_operation_indicator_position_; | |
148 drag_hint_position.Offset(-drag_hint_size.width() / 2, 0); | |
149 gfx::Rect drag_hint_bounds(drag_hint_position, drag_hint_size); | |
150 | |
151 gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size(); | |
152 drag_hint_bounds.AdjustToFit(gfx::Rect(widget_size)); | |
153 | |
154 // Draw image. | |
155 canvas->DrawImageInt(*(drag_hint->ToImageSkia()), drag_hint_bounds.x(), | |
156 drag_hint_bounds.y()); | |
157 } | |
158 | |
159 gfx::Image* DragImageView::DragHint() const { | |
160 // Select appropriate drag hint. | |
161 gfx::Image* drag_hint = | |
162 &ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
163 IDR_TOUCH_DRAG_TIP_NODROP); | |
164 if (touch_drag_operation_ & ui::DragDropTypes::DRAG_COPY) { | |
165 drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
166 IDR_TOUCH_DRAG_TIP_COPY); | |
167 } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_MOVE) { | |
168 drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
169 IDR_TOUCH_DRAG_TIP_MOVE); | |
170 } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_LINK) { | |
171 drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
172 IDR_TOUCH_DRAG_TIP_LINK); | |
173 } | |
174 return drag_hint; | |
175 } | |
176 | |
177 bool DragImageView::ShouldDrawDragHint() const { | |
178 return drag_event_source_ == ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH; | |
179 } | |
180 | |
181 gfx::Size DragImageView::GetMinimumSize() const { | |
182 gfx::Size minimum_size = drag_image_size_; | |
183 if (ShouldDrawDragHint()) | |
184 minimum_size.SetToMax(DragHint()->Size()); | |
185 return minimum_size; | |
186 } | |
187 | |
188 void DragImageView::Layout() { | |
189 View::Layout(); | |
190 | |
191 // Only consider resizing the widget for the drag hint image if we are in a | |
192 // touch initiated drag. | |
193 gfx::Image* drag_hint = DragHint(); | |
194 if (!ShouldDrawDragHint() || drag_hint->IsEmpty()) | |
195 return; | |
196 | |
197 gfx::Size drag_hint_size = drag_hint->Size(); | |
198 | |
199 // Enlarge widget if required to fit the drag hint image. | |
200 gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size(); | |
201 if (drag_hint_size.width() > widget_size.width() || | |
202 drag_hint_size.height() > widget_size.height()) { | |
203 widget_size.SetToMax(drag_hint_size); | |
204 widget_->SetSize(widget_size); | |
205 } | |
206 } | |
207 | |
208 } // namespace ash | |
OLD | NEW |