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/drag_drop/drag_image_view.h" 6 7 #include "grit/ui_resources.h" 8 #include "skia/ext/image_operations.h" 9 #include "ui/aura/window.h" 10 #include "ui/base/resource/resource_bundle.h" 11 #include "ui/compositor/dip_util.h" 12 #include "ui/gfx/canvas.h" 13 #include "ui/gfx/size_conversions.h" 14 #include "ui/views/widget/widget.h" 15 #include "ui/wm/core/shadow_types.h" 16 17 namespace ash { 18 namespace { 19 using views::Widget; 20 21 Widget* CreateDragWidget(gfx::NativeView context) { 22 Widget* drag_widget = new Widget; 23 Widget::InitParams params; 24 params.type = Widget::InitParams::TYPE_TOOLTIP; 25 params.keep_on_top = true; 26 params.context = context; 27 params.accept_events = false; 28 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 29 params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; 30 drag_widget->Init(params); 31 drag_widget->SetOpacity(0xFF); 32 drag_widget->GetNativeWindow()->set_owned_by_parent(false); 33 drag_widget->GetNativeWindow()->SetName("DragWidget"); 34 SetShadowType(drag_widget->GetNativeView(), wm::SHADOW_TYPE_NONE); 35 return drag_widget; 36 } 37 } 38 39 DragImageView::DragImageView(gfx::NativeView context, 40 ui::DragDropTypes::DragEventSource event_source) 41 : views::ImageView(), 42 drag_event_source_(event_source), 43 touch_drag_operation_(ui::DragDropTypes::DRAG_NONE) { 44 widget_.reset(CreateDragWidget(context)); 45 widget_->SetContentsView(this); 46 widget_->SetAlwaysOnTop(true); 47 48 // We are owned by the DragDropController. 49 set_owned_by_client(); 50 } 51 52 DragImageView::~DragImageView() { 53 widget_->Hide(); 54 } 55 56 void DragImageView::SetBoundsInScreen(const gfx::Rect& bounds) { 57 widget_->SetBounds(bounds); 58 widget_size_ = bounds.size(); 59 } 60 61 void DragImageView::SetScreenPosition(const gfx::Point& position) { 62 widget_->SetBounds(gfx::Rect(position, widget_size_)); 63 } 64 65 gfx::Rect DragImageView::GetBoundsInScreen() const { 66 return widget_->GetWindowBoundsInScreen(); 67 } 68 69 void DragImageView::SetWidgetVisible(bool visible) { 70 if (visible != widget_->IsVisible()) { 71 if (visible) 72 widget_->Show(); 73 else 74 widget_->Hide(); 75 } 76 } 77 78 void DragImageView::SetTouchDragOperationHintOff() { 79 // Simply set the drag type to non-touch so that no hint is drawn. 80 drag_event_source_ = ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE; 81 SchedulePaint(); 82 } 83 84 void DragImageView::SetTouchDragOperation(int operation) { 85 if (touch_drag_operation_ == operation) 86 return; 87 touch_drag_operation_ = operation; 88 SchedulePaint(); 89 } 90 91 void DragImageView::SetTouchDragOperationHintPosition( 92 const gfx::Point& position) { 93 if (touch_drag_operation_indicator_position_ == position) 94 return; 95 touch_drag_operation_indicator_position_ = position; 96 SchedulePaint(); 97 } 98 99 void DragImageView::SetOpacity(float visibility) { 100 DCHECK_GE(visibility, 0.0f); 101 DCHECK_LE(visibility, 1.0f); 102 widget_->SetOpacity(static_cast<int>(0xff * visibility)); 103 } 104 105 void DragImageView::OnPaint(gfx::Canvas* canvas) { 106 if (GetImage().isNull()) 107 return; 108 109 // |widget_size_| is in DIP. ImageSkia::size() also returns the size in DIP. 110 if (GetImage().size() == widget_size_) { 111 canvas->DrawImageInt(GetImage(), 0, 0); 112 } else { 113 float device_scale = 1; 114 if (widget_->GetNativeView() && widget_->GetNativeView()->layer()) { 115 device_scale = ui::GetDeviceScaleFactor( 116 widget_->GetNativeView()->layer()); 117 } 118 // The drag image already has device scale factor applied. But 119 // |widget_size_| is in DIP units. 120 gfx::Size scaled_widget_size = gfx::ToRoundedSize( 121 gfx::ScaleSize(widget_size_, device_scale)); 122 gfx::ImageSkiaRep image_rep = GetImage().GetRepresentation(device_scale); 123 if (image_rep.is_null()) 124 return; 125 SkBitmap scaled = skia::ImageOperations::Resize( 126 image_rep.sk_bitmap(), skia::ImageOperations::RESIZE_LANCZOS3, 127 scaled_widget_size.width(), scaled_widget_size.height()); 128 gfx::ImageSkia image_skia(gfx::ImageSkiaRep(scaled, device_scale)); 129 canvas->DrawImageInt(image_skia, 0, 0); 130 } 131 132 if (drag_event_source_ != ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH) 133 return; 134 135 // Select appropriate drag hint. 136 gfx::Image* drag_hint = 137 &ui::ResourceBundle::GetSharedInstance().GetImageNamed( 138 IDR_TOUCH_DRAG_TIP_NODROP); 139 if (touch_drag_operation_ & ui::DragDropTypes::DRAG_COPY) { 140 drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( 141 IDR_TOUCH_DRAG_TIP_COPY); 142 } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_MOVE) { 143 drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( 144 IDR_TOUCH_DRAG_TIP_MOVE); 145 } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_LINK) { 146 drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( 147 IDR_TOUCH_DRAG_TIP_LINK); 148 } 149 if (!drag_hint->IsEmpty()) { 150 gfx::Size drag_hint_size = drag_hint->Size(); 151 152 // Enlarge widget if required to fit the drag hint image. 153 if (drag_hint_size.width() > widget_size_.width() || 154 drag_hint_size.height() > widget_size_.height()) { 155 gfx::Size new_widget_size = widget_size_; 156 new_widget_size.SetToMax(drag_hint_size); 157 widget_->SetSize(new_widget_size); 158 } 159 160 // Make sure drag hint image is positioned within the widget. 161 gfx::Point drag_hint_position = touch_drag_operation_indicator_position_; 162 drag_hint_position.Offset(-drag_hint_size.width() / 2, 0); 163 gfx::Rect drag_hint_bounds(drag_hint_position, drag_hint_size); 164 drag_hint_bounds.AdjustToFit(gfx::Rect(widget_size_)); 165 166 // Draw image. 167 canvas->DrawImageInt(*(drag_hint->ToImageSkia()), 168 drag_hint_bounds.x(), drag_hint_bounds.y()); 169 } 170 } 171 172 } // namespace ash 173