Implement touch selection menu.

BUG=none
TEST=none


Review URL: http://codereview.chromium.org/7740024

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98473 0039d316-1c4b-4281-b951-d872f2087c98
parent de09c7d0
......@@ -373,13 +373,13 @@ void RenderWidgetHostViewViews::SelectRect(const gfx::Point& start,
}
bool RenderWidgetHostViewViews::IsCommandIdChecked(int command_id) const {
// TODO(varunjain): implement this and other menu delegate methods.
NOTREACHED();
return true;
}
bool RenderWidgetHostViewViews::IsCommandIdEnabled(int command_id) const {
NOTREACHED();
// TODO(varunjain): implement this.
NOTIMPLEMENTED();
return true;
}
......@@ -391,7 +391,8 @@ bool RenderWidgetHostViewViews::GetAcceleratorForCommandId(
}
void RenderWidgetHostViewViews::ExecuteCommand(int command_id) {
NOTREACHED();
// TODO(varunjain): implement this.
NOTIMPLEMENTED();
}
std::string RenderWidgetHostViewViews::GetClassName() const {
......
......@@ -4,15 +4,23 @@
#include "views/touchui/touch_selection_controller_impl.h"
#include "base/time.h"
#include "grit/ui_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/path.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size.h"
#include "ui/gfx/transform.h"
#include "views/widget/widget.h"
#include "views/controls/label.h"
#include "views/background.h"
#include "views/controls/button/button.h"
#include "views/controls/button/text_button.h"
#include "views/controls/label.h"
#include "views/layout/box_layout.h"
#include "views/widget/widget.h"
namespace {
......@@ -23,6 +31,17 @@ const int kSelectionHandleAlpha = 0x7F;
const SkColor kSelectionHandleColor =
SkColorSetA(SK_ColorBLUE, kSelectionHandleAlpha);
const int kContextMenuCommands[] = {IDS_APP_CUT,
IDS_APP_COPY,
// TODO(varunjain): PASTE is acting funny due to some gtk clipboard issue.
// Uncomment the following when that is fixed.
// IDS_APP_PASTE,
IDS_APP_DELETE,
IDS_APP_SELECT_ALL};
const int kContextMenuPadding = 2;
const int kContextMenuTimoutMs = 1000;
const int kContextMenuVerticalOffset = 10;
// Convenience struct to represent a circle shape.
struct Circle {
int radius;
......@@ -31,7 +50,7 @@ struct Circle {
};
// Creates a widget to host SelectionHandleView.
views::Widget* CreateSelectionHandleWidget() {
views::Widget* CreateTouchSelectionPopupWidget() {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.can_activate = false;
......@@ -68,7 +87,7 @@ class TouchSelectionControllerImpl::SelectionHandleView : public View {
public:
SelectionHandleView(TouchSelectionControllerImpl* controller)
: controller_(controller) {
widget_.reset(CreateSelectionHandleWidget());
widget_.reset(CreateTouchSelectionPopupWidget());
widget_->SetContentsView(this);
widget_->SetAlwaysOnTop(true);
......@@ -141,11 +160,103 @@ class TouchSelectionControllerImpl::SelectionHandleView : public View {
DISALLOW_COPY_AND_ASSIGN(SelectionHandleView);
};
// A View that displays the touch context menu.
class TouchSelectionControllerImpl::TouchContextMenuView
: public ButtonListener,
public View {
public:
TouchContextMenuView(TouchSelectionControllerImpl* controller)
: controller_(controller) {
widget_.reset(CreateTouchSelectionPopupWidget());
widget_->SetContentsView(this);
widget_->SetAlwaysOnTop(true);
// We are owned by the TouchSelectionController.
set_parent_owned(false);
SetLayoutManager(new BoxLayout(BoxLayout::kHorizontal, kContextMenuPadding,
kContextMenuPadding, kContextMenuPadding));
}
virtual ~TouchContextMenuView() {
widget_->Close();
}
virtual void SetVisible(bool visible) OVERRIDE {
// We simply show/hide the container widget.
if (visible != widget_->IsVisible()) {
if (visible)
widget_->Show();
else
widget_->Hide();
}
View::SetVisible(visible);
}
void SetScreenPosition(const gfx::Point& position) {
RefreshButtonsAndSetWidgetPosition(position);
}
gfx::Point GetScreenPosition() {
return widget_->GetClientAreaScreenBounds().origin();
}
// ButtonListener
virtual void ButtonPressed(Button* sender, const views::Event& event) {
controller_->ExecuteCommand(sender->tag());
}
private:
// Queries the client view for what elements to show in the menu and sizes
// the menu appropriately.
void RefreshButtonsAndSetWidgetPosition(const gfx::Point& position) {
RemoveAllChildViews(true);
int total_width = 0;
int height = 0;
for (size_t i = 0; i < arraysize(kContextMenuCommands); i++) {
int command_id = kContextMenuCommands[i];
if (controller_->IsCommandIdEnabled(command_id)) {
TextButton* button = new TextButton(this,
UTF16ToWide(l10n_util::GetStringUTF16(command_id)));
button->set_focusable(true);
button->set_request_focus_on_press(false);
button->set_prefix_type(TextButton::PREFIX_HIDE);
button->SetEnabledColor(SK_ColorWHITE);
button->SetHoverColor(SK_ColorWHITE);
button->set_background(
Background::CreateSolidBackground(SK_ColorBLACK));
button->set_alignment(TextButton::ALIGN_CENTER);
button->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
ui::ResourceBundle::LargeFont));
button->set_tag(command_id);
AddChildView(button);
gfx::Size button_size = button->GetPreferredSize();
total_width += button_size.width() + kContextMenuPadding;
if (height < button_size.height())
height = button_size.height();
}
}
gfx::Rect widget_bounds(position.x() - total_width / 2,
position.y() - height,
total_width,
height);
gfx::Rect monitor_bounds =
gfx::Screen::GetMonitorAreaNearestPoint(position);
widget_->SetBounds(widget_bounds.AdjustToFit(monitor_bounds));
Layout();
}
scoped_ptr<Widget> widget_;
TouchSelectionControllerImpl* controller_;
DISALLOW_COPY_AND_ASSIGN(TouchContextMenuView);
};
TouchSelectionControllerImpl::TouchSelectionControllerImpl(
TouchSelectionClientView* client_view)
: client_view_(client_view),
selection_handle_1_(new SelectionHandleView(this)),
selection_handle_2_(new SelectionHandleView(this)),
context_menu_(new TouchContextMenuView(this)),
dragging_handle_(NULL) {
}
......@@ -166,6 +277,8 @@ void TouchSelectionControllerImpl::SelectionChanged(const gfx::Point& p1,
// the start.
dragging_handle_->SetScreenPosition(screen_pos_2);
} else {
UpdateContextMenu(p1, p2);
// Check if there is any selection at all.
if (screen_pos_1 == screen_pos_2) {
selection_handle_1_->SetVisible(false);
......@@ -192,10 +305,18 @@ void TouchSelectionControllerImpl::SelectionChanged(const gfx::Point& p1,
void TouchSelectionControllerImpl::ClientViewLostFocus() {
selection_handle_1_->SetVisible(false);
selection_handle_2_->SetVisible(false);
HideContextMenu();
}
void TouchSelectionControllerImpl::SelectionHandleDragged(
const gfx::Point& drag_pos) {
// We do not want to show the context menu while dragging.
HideContextMenu();
context_menu_timer_.Start(
base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs),
this,
&TouchSelectionControllerImpl::ContextMenuTimerFired);
if (client_view_->GetWidget()) {
DCHECK(dragging_handle_);
// Find the stationary selection handle.
......@@ -225,6 +346,60 @@ void TouchSelectionControllerImpl::ConvertPointToClientView(
View::ConvertPointFromWidget(client_view_, point);
}
bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const {
return client_view_->IsCommandIdEnabled(command_id);
}
void TouchSelectionControllerImpl::ExecuteCommand(int command_id) {
HideContextMenu();
client_view_->ExecuteCommand(command_id);
}
void TouchSelectionControllerImpl::ContextMenuTimerFired() {
// Get selection end points in client_view's space.
gfx::Point p1(kSelectionHandleRadius, 0);
ConvertPointToClientView(selection_handle_1_.get(), &p1);
gfx::Point p2(kSelectionHandleRadius, 0);
ConvertPointToClientView(selection_handle_2_.get(), &p2);
// if selection is completely inside the view, we display the context menu
// in the middle of the end points on the top. Else, we show the menu on the
// top border of the view in the center.
gfx::Point menu_pos;
if (client_view_->bounds().Contains(p1) &&
client_view_->bounds().Contains(p2)) {
menu_pos.set_x((p1.x() + p2.x()) / 2);
menu_pos.set_y(std::min(p1.y(), p2.y()) - kContextMenuVerticalOffset);
} else {
menu_pos.set_x(client_view_->x() + client_view_->width() / 2);
menu_pos.set_y(client_view_->y());
}
View::ConvertPointToScreen(client_view_, &menu_pos);
context_menu_->SetScreenPosition(menu_pos);
context_menu_->SetVisible(true);
}
void TouchSelectionControllerImpl::UpdateContextMenu(const gfx::Point& p1,
const gfx::Point& p2) {
// Hide context menu to be shown when the timer fires.
HideContextMenu();
// If there is selection, we restart the context menu timer.
if (p1 != p2) {
context_menu_timer_.Start(
base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs),
this,
&TouchSelectionControllerImpl::ContextMenuTimerFired);
}
}
void TouchSelectionControllerImpl::HideContextMenu() {
context_menu_->SetVisible(false);
context_menu_timer_.Stop();
}
gfx::Point TouchSelectionControllerImpl::GetSelectionHandle1Position() {
return selection_handle_1_->GetScreenPosition();
}
......
......@@ -6,6 +6,7 @@
#define VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
#pragma once
#include "base/timer.h"
#include "ui/gfx/point.h"
#include "views/touchui/touch_selection_controller.h"
#include "views/view.h"
......@@ -32,6 +33,7 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
private:
friend class TouchSelectionControllerImplTest;
class SelectionHandleView;
class TouchContextMenuView;
// Callback to inform the client view that the selection handle has been
// dragged, hence selection may need to be updated.
......@@ -41,6 +43,21 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
// system to that of the client view.
void ConvertPointToClientView(SelectionHandleView* source, gfx::Point* point);
// Checks if the client view supports a context menu command.
bool IsCommandIdEnabled(int command_id) const;
// Sends a context menu command to the client view.
void ExecuteCommand(int command_id);
// Time to show context menu.
void ContextMenuTimerFired();
// Convenience method to update the position/visibility of the context menu.
void UpdateContextMenu(const gfx::Point& p1, const gfx::Point& p2);
// Convenience method for hiding context menu.
void HideContextMenu();
// Convenience methods for testing.
gfx::Point GetSelectionHandle1Position();
gfx::Point GetSelectionHandle2Position();
......@@ -50,6 +67,12 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
TouchSelectionClientView* client_view_;
scoped_ptr<SelectionHandleView> selection_handle_1_;
scoped_ptr<SelectionHandleView> selection_handle_2_;
scoped_ptr<TouchContextMenuView> context_menu_;
// Timer to trigger |context_menu| (|context_menu| is not shown if the
// selection handles are being updated. It appears only when the handles are
// stationary for a certain amount of time).
base::OneShotTimer<TouchSelectionControllerImpl> context_menu_timer_;
// Pointer to the SelectionHandleView being dragged during a drag session.
SelectionHandleView* dragging_handle_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment