diff options
Diffstat (limited to 'chromium/ash/drag_drop/drag_image_view.cc')
-rw-r--r-- | chromium/ash/drag_drop/drag_image_view.cc | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/chromium/ash/drag_drop/drag_image_view.cc b/chromium/ash/drag_drop/drag_image_view.cc new file mode 100644 index 00000000000..d9a9e88c53c --- /dev/null +++ b/chromium/ash/drag_drop/drag_image_view.cc @@ -0,0 +1,175 @@ +// 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/corewm/shadow_types.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace internal { + +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(), views::corewm::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 internal +} // namespace ash |