| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/drag_drop/drag_image_view.h" |
| |
| #include "grit/ui_resources.h" |
| #include "skia/ext/image_operations.h" |
| #include "ui/aura/window.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/compositor/dip_util.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/size_conversions.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/wm/core/shadow_types.h" |
| |
| namespace ash { |
| namespace { |
| using views::Widget; |
| |
| Widget* CreateDragWidget(gfx::NativeView context) { |
| Widget* drag_widget = new Widget; |
| Widget::InitParams params; |
| params.type = Widget::InitParams::TYPE_TOOLTIP; |
| params.keep_on_top = true; |
| params.context = context; |
| params.accept_events = false; |
| params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; |
| drag_widget->Init(params); |
| drag_widget->SetOpacity(0xFF); |
| drag_widget->GetNativeWindow()->set_owned_by_parent(false); |
| drag_widget->GetNativeWindow()->SetName("DragWidget"); |
| SetShadowType(drag_widget->GetNativeView(), wm::SHADOW_TYPE_NONE); |
| return drag_widget; |
| } |
| } |
| |
| DragImageView::DragImageView(gfx::NativeView context, |
| ui::DragDropTypes::DragEventSource event_source) |
| : views::ImageView(), |
| drag_event_source_(event_source), |
| touch_drag_operation_(ui::DragDropTypes::DRAG_NONE) { |
| widget_.reset(CreateDragWidget(context)); |
| widget_->SetContentsView(this); |
| widget_->SetAlwaysOnTop(true); |
| |
| // We are owned by the DragDropController. |
| set_owned_by_client(); |
| } |
| |
| DragImageView::~DragImageView() { |
| widget_->Hide(); |
| } |
| |
| void DragImageView::SetBoundsInScreen(const gfx::Rect& bounds) { |
| widget_->SetBounds(bounds); |
| widget_size_ = bounds.size(); |
| } |
| |
| void DragImageView::SetScreenPosition(const gfx::Point& position) { |
| widget_->SetBounds(gfx::Rect(position, widget_size_)); |
| } |
| |
| gfx::Rect DragImageView::GetBoundsInScreen() const { |
| return widget_->GetWindowBoundsInScreen(); |
| } |
| |
| void DragImageView::SetWidgetVisible(bool visible) { |
| if (visible != widget_->IsVisible()) { |
| if (visible) |
| widget_->Show(); |
| else |
| widget_->Hide(); |
| } |
| } |
| |
| void DragImageView::SetTouchDragOperationHintOff() { |
| // Simply set the drag type to non-touch so that no hint is drawn. |
| drag_event_source_ = ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE; |
| SchedulePaint(); |
| } |
| |
| void DragImageView::SetTouchDragOperation(int operation) { |
| if (touch_drag_operation_ == operation) |
| return; |
| touch_drag_operation_ = operation; |
| SchedulePaint(); |
| } |
| |
| void DragImageView::SetTouchDragOperationHintPosition( |
| const gfx::Point& position) { |
| if (touch_drag_operation_indicator_position_ == position) |
| return; |
| touch_drag_operation_indicator_position_ = position; |
| SchedulePaint(); |
| } |
| |
| void DragImageView::SetOpacity(float visibility) { |
| DCHECK_GE(visibility, 0.0f); |
| DCHECK_LE(visibility, 1.0f); |
| widget_->SetOpacity(static_cast<int>(0xff * visibility)); |
| } |
| |
| void DragImageView::OnPaint(gfx::Canvas* canvas) { |
| if (GetImage().isNull()) |
| return; |
| |
| // |widget_size_| is in DIP. ImageSkia::size() also returns the size in DIP. |
| if (GetImage().size() == widget_size_) { |
| canvas->DrawImageInt(GetImage(), 0, 0); |
| } else { |
| float device_scale = 1; |
| if (widget_->GetNativeView() && widget_->GetNativeView()->layer()) { |
| device_scale = ui::GetDeviceScaleFactor( |
| widget_->GetNativeView()->layer()); |
| } |
| // The drag image already has device scale factor applied. But |
| // |widget_size_| is in DIP units. |
| gfx::Size scaled_widget_size = gfx::ToRoundedSize( |
| gfx::ScaleSize(widget_size_, device_scale)); |
| gfx::ImageSkiaRep image_rep = GetImage().GetRepresentation(device_scale); |
| if (image_rep.is_null()) |
| return; |
| SkBitmap scaled = skia::ImageOperations::Resize( |
| image_rep.sk_bitmap(), skia::ImageOperations::RESIZE_LANCZOS3, |
| scaled_widget_size.width(), scaled_widget_size.height()); |
| gfx::ImageSkia image_skia(gfx::ImageSkiaRep(scaled, device_scale)); |
| canvas->DrawImageInt(image_skia, 0, 0); |
| } |
| |
| if (drag_event_source_ != ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH) |
| return; |
| |
| // Select appropriate drag hint. |
| gfx::Image* drag_hint = |
| &ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| IDR_TOUCH_DRAG_TIP_NODROP); |
| if (touch_drag_operation_ & ui::DragDropTypes::DRAG_COPY) { |
| drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| IDR_TOUCH_DRAG_TIP_COPY); |
| } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_MOVE) { |
| drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| IDR_TOUCH_DRAG_TIP_MOVE); |
| } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_LINK) { |
| drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| IDR_TOUCH_DRAG_TIP_LINK); |
| } |
| if (!drag_hint->IsEmpty()) { |
| gfx::Size drag_hint_size = drag_hint->Size(); |
| |
| // Enlarge widget if required to fit the drag hint image. |
| if (drag_hint_size.width() > widget_size_.width() || |
| drag_hint_size.height() > widget_size_.height()) { |
| gfx::Size new_widget_size = widget_size_; |
| new_widget_size.SetToMax(drag_hint_size); |
| widget_->SetSize(new_widget_size); |
| } |
| |
| // Make sure drag hint image is positioned within the widget. |
| gfx::Point drag_hint_position = touch_drag_operation_indicator_position_; |
| drag_hint_position.Offset(-drag_hint_size.width() / 2, 0); |
| gfx::Rect drag_hint_bounds(drag_hint_position, drag_hint_size); |
| drag_hint_bounds.AdjustToFit(gfx::Rect(widget_size_)); |
| |
| // Draw image. |
| canvas->DrawImageInt(*(drag_hint->ToImageSkia()), |
| drag_hint_bounds.x(), drag_hint_bounds.y()); |
| } |
| } |
| |
| } // namespace ash |