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/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