blob: a353c59a7fccd7f13457d4f73226ea3d4064445d [file] [log] [blame]
// Copyright 2015 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 "ui/touch_selection/touch_handle_drawable_aura.h"
#include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
#include "ui/aura_extra/image_window_delegate.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/hit_test.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/resources/grit/ui_resources.h"
namespace ui {
namespace {
// The distance by which a handle image is offset from the focal point (i.e.
// text baseline) downwards.
const int kSelectionHandleVerticalVisualOffset = 2;
// The padding around the selection handle image can be used to extend the
// handle window so that touch events near the selection handle image are
// targeted to the selection handle window.
const int kSelectionHandlePadding = 0;
// Epsilon value used to compare float values to zero.
const float kEpsilon = 1e-8f;
// Returns the appropriate handle image based on the handle orientation.
gfx::Image* GetHandleImage(TouchHandleOrientation orientation) {
int resource_id = 0;
switch (orientation) {
case TouchHandleOrientation::LEFT:
resource_id = IDR_TEXT_SELECTION_HANDLE_LEFT;
break;
case TouchHandleOrientation::CENTER:
resource_id = IDR_TEXT_SELECTION_HANDLE_CENTER;
break;
case TouchHandleOrientation::RIGHT:
resource_id = IDR_TEXT_SELECTION_HANDLE_RIGHT;
break;
case TouchHandleOrientation::UNDEFINED:
NOTREACHED() << "Invalid touch handle bound type.";
return nullptr;
};
return &ResourceBundle::GetSharedInstance().GetImageNamed(resource_id);
}
bool IsNearlyZero(float value) {
return std::abs(value) < kEpsilon;
}
} // namespace
TouchHandleDrawableAura::TouchHandleDrawableAura(aura::Window* parent)
: window_delegate_(new aura_extra::ImageWindowDelegate),
window_(new aura::Window(window_delegate_)),
enabled_(false),
alpha_(0),
orientation_(TouchHandleOrientation::UNDEFINED) {
window_delegate_->set_image_offset(gfx::Vector2d(kSelectionHandlePadding,
kSelectionHandlePadding));
window_delegate_->set_background_color(SK_ColorTRANSPARENT);
window_->SetTransparent(true);
window_->Init(LAYER_TEXTURED);
window_->set_owned_by_parent(false);
window_->set_ignore_events(true);
parent->AddChild(window_.get());
}
TouchHandleDrawableAura::~TouchHandleDrawableAura() {
}
void TouchHandleDrawableAura::UpdateBounds() {
gfx::RectF new_bounds = relative_bounds_;
new_bounds.Offset(focal_position_.x(), focal_position_.y());
window_->SetBounds(gfx::ToEnclosingRect(new_bounds));
}
bool TouchHandleDrawableAura::IsVisible() const {
return enabled_ && !IsNearlyZero(alpha_);
}
void TouchHandleDrawableAura::SetEnabled(bool enabled) {
if (enabled == enabled_)
return;
enabled_ = enabled;
if (IsVisible())
window_->Show();
else
window_->Hide();
}
void TouchHandleDrawableAura::SetOrientation(
TouchHandleOrientation orientation) {
if (orientation_ == orientation)
return;
orientation_ = orientation;
gfx::Image* image = GetHandleImage(orientation);
window_delegate_->SetImage(*image);
// Calculate the relative bounds.
gfx::Size image_size = image->Size();
int window_width = image_size.width() + 2 * kSelectionHandlePadding;
int window_height = image_size.height() + 2 * kSelectionHandlePadding;
// Due to the shape of the handle images, the window is aligned differently to
// the selection bound depending on the orientation.
int window_left = 0;
switch (orientation) {
case TouchHandleOrientation::LEFT:
window_left = -image_size.width() - kSelectionHandlePadding;
break;
case TouchHandleOrientation::RIGHT:
window_left = -kSelectionHandlePadding;
break;
case TouchHandleOrientation::CENTER:
window_left = -window_width / 2;
break;
case TouchHandleOrientation::UNDEFINED:
NOTREACHED() << "Undefined handle orientation.";
break;
};
relative_bounds_ = gfx::RectF(
window_left,
kSelectionHandleVerticalVisualOffset - kSelectionHandlePadding,
window_width,
window_height);
UpdateBounds();
}
void TouchHandleDrawableAura::SetAlpha(float alpha) {
if (alpha == alpha_)
return;
alpha_ = alpha;
window_->layer()->SetOpacity(alpha_);
if (IsVisible())
window_->Show();
else
window_->Hide();
}
void TouchHandleDrawableAura::SetFocus(const gfx::PointF& position) {
focal_position_ = position;
UpdateBounds();
}
gfx::RectF TouchHandleDrawableAura::GetVisibleBounds() const {
gfx::RectF bounds(window_->bounds());
bounds.Inset(kSelectionHandlePadding,
kSelectionHandlePadding + kSelectionHandleVerticalVisualOffset,
kSelectionHandlePadding,
kSelectionHandlePadding);
return bounds;
}
} // namespace ui