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