| // Copyright 2014 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. |
| |
| #ifndef UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_ |
| #define UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_ |
| |
| #include "base/macros.h" |
| #include "base/time/time.h" |
| #include "ui/gfx/geometry/point_f.h" |
| #include "ui/gfx/geometry/rect_f.h" |
| #include "ui/gfx/geometry/vector2d_f.h" |
| #include "ui/gfx/selection_bound.h" |
| #include "ui/touch_selection/longpress_drag_selector.h" |
| #include "ui/touch_selection/selection_event_type.h" |
| #include "ui/touch_selection/touch_handle.h" |
| #include "ui/touch_selection/touch_handle_orientation.h" |
| #include "ui/touch_selection/ui_touch_selection_export.h" |
| |
| namespace ui { |
| class MotionEvent; |
| |
| // Interface through which |TouchSelectionController| issues selection-related |
| // commands, notifications and requests. |
| class UI_TOUCH_SELECTION_EXPORT TouchSelectionControllerClient { |
| public: |
| virtual ~TouchSelectionControllerClient() {} |
| |
| virtual bool SupportsAnimation() const = 0; |
| virtual void SetNeedsAnimate() = 0; |
| virtual void MoveCaret(const gfx::PointF& position) = 0; |
| virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) = 0; |
| virtual void SelectBetweenCoordinates(const gfx::PointF& base, |
| const gfx::PointF& extent) = 0; |
| virtual void OnSelectionEvent(SelectionEventType event) = 0; |
| virtual void OnDragUpdate(const gfx::PointF& position) = 0; |
| virtual std::unique_ptr<TouchHandleDrawable> CreateDrawable() = 0; |
| virtual void DidScroll() = 0; |
| }; |
| |
| // Controller for manipulating text selection via touch input. |
| class UI_TOUCH_SELECTION_EXPORT TouchSelectionController |
| : public TouchHandleClient, |
| public LongPressDragSelectorClient { |
| public: |
| enum ActiveStatus { |
| INACTIVE, |
| INSERTION_ACTIVE, |
| SELECTION_ACTIVE, |
| }; |
| |
| struct UI_TOUCH_SELECTION_EXPORT Config { |
| Config(); |
| ~Config(); |
| |
| // Maximum allowed time for handle tap detection. Defaults to 300 ms. |
| base::TimeDelta max_tap_duration; |
| |
| // Defaults to 8 DIPs. |
| float tap_slop; |
| |
| // Controls whether adaptive orientation for selection handles is enabled. |
| // Defaults to false. |
| bool enable_adaptive_handle_orientation; |
| |
| // Controls whether drag selection after a longpress is enabled. |
| // Defaults to false. |
| bool enable_longpress_drag_selection; |
| |
| // Should we hide the active handle. |
| bool hide_active_handle; |
| }; |
| |
| TouchSelectionController(TouchSelectionControllerClient* client, |
| const Config& config); |
| ~TouchSelectionController() override; |
| |
| // To be called when the selection bounds have changed. |
| // Note that such updates will trigger handle updates only if preceded |
| // by an appropriate call to allow automatic showing. |
| void OnSelectionBoundsChanged(const gfx::SelectionBound& start, |
| const gfx::SelectionBound& end); |
| |
| // To be called when the viewport rect has been changed. This is used for |
| // setting the state of the handles. |
| void OnViewportChanged(const gfx::RectF viewport_rect); |
| |
| // Allows touch-dragging of the handle. |
| // Returns true iff the event was consumed, in which case the caller should |
| // cease further handling of the event. |
| bool WillHandleTouchEvent(const MotionEvent& event); |
| |
| // To be called before forwarding a tap event. |
| // |tap_count| is tap index in a repeated sequence, i.e., 1 for the first |
| // tap, 2 for the second tap, etc... |
| void HandleTapEvent(const gfx::PointF& location, int tap_count); |
| |
| // To be called before forwarding a longpress event. |
| void HandleLongPressEvent(base::TimeTicks event_time, |
| const gfx::PointF& location); |
| |
| // To be called before forwarding a gesture scroll begin event to prevent |
| // long-press drag. |
| void OnScrollBeginEvent(); |
| |
| // Hide the handles and suppress bounds updates until the next explicit |
| // showing allowance. |
| void HideAndDisallowShowingAutomatically(); |
| |
| // Override the handle visibility according to |hidden|. |
| void SetTemporarilyHidden(bool hidden); |
| |
| // Ticks an active animation, as requested to the client by |SetNeedsAnimate|. |
| // Returns true if an animation is active and requires further ticking. |
| bool Animate(base::TimeTicks animate_time); |
| |
| // Returns the rect between the two active selection bounds. If just one of |
| // the bounds is visible, or both bounds are visible and on the same line, |
| // the rect is simply a one-dimensional rect of that bound. If no selection |
| // is active, an empty rect will be returned. |
| gfx::RectF GetRectBetweenBounds() const; |
| // Returns the rect between the selection bounds (as above) but clipped by |
| // occluding layers. |
| gfx::RectF GetVisibleRectBetweenBounds() const; |
| |
| // Returns the visible rect of specified touch handle. For an active insertion |
| // these values will be identical. |
| gfx::RectF GetStartHandleRect() const; |
| gfx::RectF GetEndHandleRect() const; |
| |
| // Return the handle height of visible touch handle. This value will be zero |
| // when no handle is visible. |
| float GetTouchHandleHeight() const; |
| |
| // Returns the focal point of the start and end bounds, as defined by |
| // their bottom coordinate. |
| const gfx::PointF& GetStartPosition() const; |
| const gfx::PointF& GetEndPosition() const; |
| |
| const gfx::SelectionBound& start() const { return start_; } |
| const gfx::SelectionBound& end() const { return end_; } |
| |
| ActiveStatus active_status() const { return active_status_; } |
| |
| private: |
| friend class TouchSelectionControllerTestApi; |
| |
| enum InputEventType { TAP, REPEATED_TAP, LONG_PRESS, INPUT_EVENT_TYPE_NONE }; |
| |
| bool WillHandleTouchEventImpl(const MotionEvent& event); |
| |
| // TouchHandleClient implementation. |
| void OnDragBegin(const TouchSelectionDraggable& draggable, |
| const gfx::PointF& drag_position) override; |
| void OnDragUpdate(const TouchSelectionDraggable& draggable, |
| const gfx::PointF& drag_position) override; |
| void OnDragEnd(const TouchSelectionDraggable& draggable) override; |
| bool IsWithinTapSlop(const gfx::Vector2dF& delta) const override; |
| void OnHandleTapped(const TouchHandle& handle) override; |
| void SetNeedsAnimate() override; |
| std::unique_ptr<TouchHandleDrawable> CreateDrawable() override; |
| base::TimeDelta GetMaxTapDuration() const override; |
| bool IsAdaptiveHandleOrientationEnabled() const override; |
| |
| // LongPressDragSelectorClient implementation. |
| void OnLongPressDragActiveStateChanged() override; |
| gfx::PointF GetSelectionStart() const override; |
| gfx::PointF GetSelectionEnd() const override; |
| |
| void OnInsertionChanged(); |
| void OnSelectionChanged(); |
| |
| // Returns true if insertion mode was newly (re)activated. |
| bool ActivateInsertionIfNecessary(); |
| void DeactivateInsertion(); |
| // Returns true if selection mode was newly (re)activated. |
| bool ActivateSelectionIfNecessary(); |
| void DeactivateSelection(); |
| void UpdateHandleLayoutIfNecessary(); |
| |
| bool WillHandleTouchEventForLongPressDrag(const MotionEvent& event); |
| void SetTemporarilyHiddenForLongPressDrag(bool hidden); |
| void RefreshHandleVisibility(); |
| |
| // Returns the y-coordinate of middle point of selection bound corresponding |
| // to the active selection or insertion handle. If there is no active handle, |
| // returns 0.0. |
| float GetActiveHandleMiddleY() const; |
| |
| void HideHandles(); |
| |
| gfx::Vector2dF GetStartLineOffset() const; |
| gfx::Vector2dF GetEndLineOffset() const; |
| bool GetStartVisible() const; |
| bool GetEndVisible() const; |
| TouchHandle::AnimationStyle GetAnimationStyle(bool was_active) const; |
| |
| void LogSelectionEnd(); |
| |
| TouchSelectionControllerClient* const client_; |
| const Config config_; |
| |
| InputEventType response_pending_input_event_; |
| |
| // The bounds at the begin and end of the selection, which might be vertical |
| // or horizontal line and represents the position of the touch handles or |
| // caret. |
| gfx::SelectionBound start_; |
| gfx::SelectionBound end_; |
| TouchHandleOrientation start_orientation_; |
| TouchHandleOrientation end_orientation_; |
| |
| ActiveStatus active_status_; |
| |
| std::unique_ptr<TouchHandle> insertion_handle_; |
| |
| std::unique_ptr<TouchHandle> start_selection_handle_; |
| std::unique_ptr<TouchHandle> end_selection_handle_; |
| |
| bool temporarily_hidden_; |
| |
| // Whether to use the start bound (if false, the end bound) for computing the |
| // appropriate text line offset when performing a selection drag. This helps |
| // ensure that the initial selection induced by the drag doesn't "jump" |
| // between lines. |
| bool anchor_drag_to_selection_start_; |
| |
| // Longpress drag allows direct manipulation of longpress-initiated selection. |
| LongPressDragSelector longpress_drag_selector_; |
| |
| gfx::RectF viewport_rect_; |
| |
| base::TimeTicks selection_start_time_; |
| // Whether a selection handle was dragged during the current 'selection |
| // session' - i.e. since the current selection has been activated. |
| bool selection_handle_dragged_; |
| |
| // Determines whether the entire touch sequence should be consumed or not. |
| bool consume_touch_sequence_; |
| |
| bool show_touch_handles_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TouchSelectionController); |
| }; |
| |
| } // namespace ui |
| |
| #endif // UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_ |