| 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 |