Home | History | Annotate | Download | only in drag_drop
      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