0

capture_mode: Initial land of capture region feature.

See screen cast in bug comment 1 for a video of what is included and not
included in this CL.

Included:
  - Dragging to select a region
  - After first drag, fine tuning via affordance circles
  - Button to capture region (can be reused for fullscreen and window
    capture)
  - Switching to and from capture region source
Not included:
  - Nudge for tablet mode (see specs)
  - Motion/animations
  - Styling for buttons
  - Drop shadow for border and affordance circles
  - Partial magnifier for affordance circle presses
  - Cursor changes

The basics of this CL is to provide a UI to select a region. The
selection has two phases, a quick selection phase to quickly grab a
region, then a fine tuning phase where users can resize/reposition the
region with some drag affordances.

For a capture region session, we add two widgets to have supporting
text and buttons, and a struct that holds data needed to draw the rest
of the UI onto the layer. The layer is updated when the selection
region has been updated from drag events.

For phase two, we use a simple formula to determine which affordance
has been pressed down on, if any. If an affordance was pressed on, we
allow resizing, but one or two points stay the same. These are stored
in the struct as anchor points, and used to compute the new selection
region when there is a drag event.

Test: manual
Bug: 1120132
Change-Id: If9c461d82306666cbfa9be7fcd521bd6caeec331
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2404945
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Commit-Queue: Sammie Quon <sammiequon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807318}
This commit is contained in:
Sammie Quon
2020-09-16 03:12:13 +00:00
committed by Commit Bot
parent bcc673eda8
commit e8381eff4d
3 changed files with 484 additions and 31 deletions

@ -4,16 +4,16 @@
#include "ash/capture_mode/capture_mode_session.h"
#include <memory>
#include "ash/capture_mode/capture_mode_bar_view.h"
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/display/mouse_cursor_event_filter.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
#include "ash/style/ash_color_provider.h"
#include "ash/wm/mru_window_tracker.h"
#include "base/memory/ptr_util.h"
#include "cc/paint/paint_flags.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_type.h"
@ -21,8 +21,13 @@
#include "ui/events/types/event_type.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/label.h"
namespace ash {
@ -30,6 +35,17 @@ namespace {
constexpr int kBorderStrokePx = 2;
// The visual radius of the drag affordance circles which are shown while
// resizing a drag region.
constexpr int kAffordanceCircleRadiusDp = 5;
// The hit radius of the drag affordance circles touch events.
constexpr int kAffordanceCircleTouchHitRadiusDp = 16;
constexpr int kSizeLabelYDistanceFromRegionDp = 8;
constexpr SkColor kRegionBorderColor = SK_ColorWHITE;
// Blue300 at 30%.
constexpr SkColor kCaptureRegionColor = SkColorSetA(gfx::kGoogleBlue300, 77);
@ -49,6 +65,66 @@ aura::Window* GetParentContainer(aura::Window* root) {
return root->GetChildById(kShellWindowId_OverlayContainer);
}
// Retrieves the point on the |rect| associated with |position|.
gfx::Point GetLocationForPosition(const gfx::Rect& rect,
FineTunePosition position) {
switch (position) {
case FineTunePosition::kTopLeft:
return rect.origin();
case FineTunePosition::kTopCenter:
return rect.top_center();
case FineTunePosition::kTopRight:
return rect.top_right();
case FineTunePosition::kRightCenter:
return rect.right_center();
case FineTunePosition::kBottomRight:
return rect.bottom_right();
case FineTunePosition::kBottomCenter:
return rect.bottom_center();
case FineTunePosition::kBottomLeft:
return rect.bottom_left();
case FineTunePosition::kLeftCenter:
return rect.left_center();
default:
break;
}
NOTREACHED();
return gfx::Point();
}
// Returns the smallest rect that contains all of |points|.
gfx::Rect GetRectEnclosingPoints(const std::vector<gfx::Point>& points) {
DCHECK_GE(points.size(), 2u);
int x = INT_MAX;
int y = INT_MAX;
int right = INT_MIN;
int bottom = INT_MIN;
for (const gfx::Point& point : points) {
x = std::min(point.x(), x);
y = std::min(point.y(), y);
right = std::max(point.x(), right);
bottom = std::max(point.y(), bottom);
}
return gfx::Rect(x, y, right - x, bottom - y);
}
// Returns the widget init params needed to create a widget associated with a
// capture session.
views::Widget::InitParams CreateWidgetParams(aura::Window* parent,
const gfx::Rect& bounds,
const std::string& name) {
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
params.parent = parent;
params.bounds = bounds;
params.name = name;
return params;
}
} // namespace
CaptureModeSession::CaptureModeSession(CaptureModeController* controller,
@ -67,15 +143,8 @@ CaptureModeSession::CaptureModeSession(CaptureModeController* controller,
parent->layer()->Add(layer());
layer()->SetBounds(parent->bounds());
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
params.parent = parent;
params.bounds = CaptureModeBarView::GetBounds(root);
params.name = "CaptureModeBarWidget";
capture_mode_bar_widget_.Init(std::move(params));
capture_mode_bar_widget_.Init(CreateWidgetParams(
parent, CaptureModeBarView::GetBounds(root), "CaptureModeBarWidget"));
capture_mode_bar_widget_.SetContentsView(
base::WrapUnique(capture_mode_bar_view_));
capture_mode_bar_widget_.Show();
@ -100,6 +169,7 @@ aura::Window* CaptureModeSession::GetSelectedWindow() const {
void CaptureModeSession::OnCaptureSourceChanged(CaptureModeSource new_source) {
capture_mode_bar_view_->OnCaptureSourceChanged(new_source);
SetMouseWarpEnabled(new_source != CaptureModeSource::kRegion);
UpdateCaptureRegionWidgets();
layer()->SchedulePaint(layer()->bounds());
}
@ -136,11 +206,22 @@ void CaptureModeSession::OnKeyEvent(ui::KeyEvent* event) {
}
void CaptureModeSession::OnMouseEvent(ui::MouseEvent* event) {
// TODO(afakhry): Fill in here.
OnLocatedEvent(event, /*is_touch=*/false);
}
void CaptureModeSession::OnTouchEvent(ui::TouchEvent* event) {
// TODO(afakhry): Fill in here.
OnLocatedEvent(event, /*is_touch=*/true);
}
void CaptureModeSession::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (!capture_button_widget_)
return;
DCHECK_EQ(static_cast<views::LabelButton*>(
capture_button_widget_->GetContentsView()),
sender);
controller_->PerformCapture(); // |this| is destroyed here.
}
gfx::Rect CaptureModeSession::GetSelectedWindowBounds() const {
@ -150,15 +231,12 @@ gfx::Rect CaptureModeSession::GetSelectedWindowBounds() const {
void CaptureModeSession::RefreshStackingOrder(aura::Window* parent_container) {
DCHECK(parent_container);
auto* widget_layer = capture_mode_bar_widget_.GetNativeWindow()->layer();
auto* capture_mode_bar_layer = capture_mode_bar_widget_.GetLayer();
auto* overlay_layer = layer();
auto* parent_container_layer = parent_container->layer();
DCHECK_EQ(parent_container_layer, overlay_layer->parent());
DCHECK_EQ(parent_container_layer, widget_layer->parent());
parent_container_layer->StackAtTop(overlay_layer);
parent_container_layer->StackAtTop(widget_layer);
parent_container_layer->StackAtTop(capture_mode_bar_layer);
}
void CaptureModeSession::PaintCaptureRegion(gfx::Canvas* canvas) {
@ -187,22 +265,320 @@ void CaptureModeSession::PaintCaptureRegion(gfx::Canvas* canvas) {
const float dsf = canvas->UndoDeviceScaleFactor();
region = gfx::ScaleToEnclosingRect(region, dsf);
canvas->FillRect(region, SK_ColorBLACK, SkBlendMode::kClear);
canvas->FillRect(region, kCaptureRegionColor);
if (!adjustable_region) {
canvas->FillRect(region, SK_ColorTRANSPARENT, SkBlendMode::kClear);
canvas->FillRect(region, kCaptureRegionColor);
return;
}
if (!adjustable_region)
region.Inset(-kBorderStrokePx, -kBorderStrokePx);
canvas->FillRect(region, SK_ColorTRANSPARENT, SkBlendMode::kClear);
canvas->DrawRect(gfx::RectF(region), kRegionBorderColor);
if (is_select_phase_)
return;
// TODO(afakhry): For adjustable regions, we may change the colors. Also,
// paint the drag points at the corners.
region.Inset(-kBorderStrokePx, -kBorderStrokePx);
// Do not show affordance circles when repositioning the whole region.
if (fine_tune_position_ == FineTunePosition::kCenter)
return;
// Draw the drag affordance circles.
// TODO(sammiequon): Draw a drop shadow for the affordance circles and the
// border.
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kStroke_Style);
// TODO(afakhry): Update to match the specs.
flags.setColor(gfx::kGoogleBlue200);
flags.setStrokeWidth(SkIntToScalar(kBorderStrokePx));
canvas->DrawRect(region, flags);
flags.setColor(kRegionBorderColor);
flags.setStyle(cc::PaintFlags::kFill_Style);
canvas->DrawCircle(region.origin(), kAffordanceCircleRadiusDp, flags);
canvas->DrawCircle(region.top_center(), kAffordanceCircleRadiusDp, flags);
canvas->DrawCircle(region.top_right(), kAffordanceCircleRadiusDp, flags);
canvas->DrawCircle(region.left_center(), kAffordanceCircleRadiusDp, flags);
canvas->DrawCircle(region.right_center(), kAffordanceCircleRadiusDp, flags);
canvas->DrawCircle(region.bottom_left(), kAffordanceCircleRadiusDp, flags);
canvas->DrawCircle(region.bottom_center(), kAffordanceCircleRadiusDp, flags);
canvas->DrawCircle(region.bottom_right(), kAffordanceCircleRadiusDp, flags);
}
void CaptureModeSession::OnLocatedEvent(ui::LocatedEvent* event,
bool is_touch) {
// No need to handle events if the current source is not region.
if (controller_->source() != CaptureModeSource::kRegion)
return;
gfx::Point location = event->location();
aura::Window* source = static_cast<aura::Window*>(event->target());
aura::Window::ConvertPointToTarget(source, current_root_, &location);
// Let the capture button handle any events within its bounds.
if (capture_button_widget_ &&
capture_button_widget_->GetNativeWindow()->bounds().Contains(location)) {
return;
}
// Allow events that are located on the capture mode bar to pass through so we
// can click the buttons.
if (!CaptureModeBarView::GetBounds(current_root_).Contains(location)) {
event->SetHandled();
event->StopPropagation();
}
switch (event->type()) {
case ui::ET_MOUSE_PRESSED:
case ui::ET_TOUCH_PRESSED:
OnLocatedEventPressed(location, is_touch);
break;
case ui::ET_MOUSE_DRAGGED:
case ui::ET_TOUCH_MOVED:
OnLocatedEventDragged(location);
break;
case ui::ET_MOUSE_RELEASED:
case ui::ET_TOUCH_RELEASED:
OnLocatedEventReleased(location);
break;
default:
break;
}
}
void CaptureModeSession::OnLocatedEventPressed(
const gfx::Point& location_in_root,
bool is_touch) {
initial_location_in_root_ = location_in_root;
previous_location_in_root_ = location_in_root;
if (is_select_phase_)
return;
// Calculate the position and anchor points of the current pressed event.
fine_tune_position_ = FineTunePosition::kNone;
// In the case of overlapping affordances, prioritize the bottomm right
// corner, then the rest of the corners, then the edges.
static const std::vector<FineTunePosition> drag_positions = {
FineTunePosition::kBottomRight, FineTunePosition::kBottomLeft,
FineTunePosition::kTopLeft, FineTunePosition::kTopRight,
FineTunePosition::kBottomCenter, FineTunePosition::kLeftCenter,
FineTunePosition::kTopCenter, FineTunePosition::kRightCenter};
const int hit_radius =
is_touch ? kAffordanceCircleTouchHitRadiusDp : kAffordanceCircleRadiusDp;
const int hit_radius_squared = hit_radius * hit_radius;
for (FineTunePosition position : drag_positions) {
const gfx::Point position_location =
GetLocationForPosition(controller_->user_capture_region(), position);
// If |location_in_root| is within |hit_radius| of |position_location| for
// both x and y, then |position| is the current pressed down affordance.
if ((position_location - location_in_root).LengthSquared() <=
hit_radius_squared) {
fine_tune_position_ = position;
break;
}
}
if (fine_tune_position_ == FineTunePosition::kNone) {
// If the point is outside the capture region and not on the capture bar,
// restart to the select phase.
if (controller_->user_capture_region().Contains(location_in_root)) {
fine_tune_position_ = FineTunePosition::kCenter;
} else if (!CaptureModeBarView::GetBounds(current_root_)
.Contains(location_in_root)) {
is_select_phase_ = true;
UpdateCaptureRegion(gfx::Rect());
}
return;
}
anchor_points_ = GetAnchorPointsForPosition(fine_tune_position_);
}
void CaptureModeSession::OnLocatedEventDragged(
const gfx::Point& location_in_root) {
const gfx::Point previous_location_in_root = previous_location_in_root_;
previous_location_in_root_ = location_in_root;
// For the select phase, the select region is the rectangle formed by the
// press location and the current locatiion.
if (is_select_phase_) {
UpdateCaptureRegion(
GetRectEnclosingPoints({initial_location_in_root_, location_in_root}));
return;
}
if (fine_tune_position_ == FineTunePosition::kNone)
return;
// For a reposition, offset the old select region by the difference between
// the current location and the previous location, but do not let the select
// region go offscreen.
if (fine_tune_position_ == FineTunePosition::kCenter) {
gfx::Rect new_capture_region = controller_->user_capture_region();
new_capture_region.Offset(location_in_root - previous_location_in_root);
new_capture_region.AdjustToFit(current_root_->bounds());
UpdateCaptureRegion(new_capture_region);
return;
}
// The new region is defined by the rectangle which encloses the anchor
// point(s) and |location_in_root|.
std::vector<gfx::Point> points = anchor_points_;
DCHECK(!points.empty());
points.push_back(location_in_root);
UpdateCaptureRegion(GetRectEnclosingPoints(points));
}
void CaptureModeSession::OnLocatedEventReleased(
const gfx::Point& location_in_root) {
fine_tune_position_ = FineTunePosition::kNone;
anchor_points_.clear();
// Do a repaint to show the affordance circles. See UpdateCaptureRegion to see
// how damage is calculated.
gfx::Rect damage_region = controller_->user_capture_region();
damage_region.Inset(
gfx::Insets(-kAffordanceCircleRadiusDp - kBorderStrokePx));
layer()->SchedulePaint(damage_region);
if (!is_select_phase_)
return;
// After first release event, we advance to the next phase.
is_select_phase_ = false;
UpdateCaptureRegionWidgets();
}
void CaptureModeSession::UpdateCaptureRegion(
const gfx::Rect& new_capture_region) {
const gfx::Rect old_capture_region = controller_->user_capture_region();
if (old_capture_region == new_capture_region)
return;
// Calculate the region that has been damaged and repaint the layer. Add some
// extra padding to make sure the border and affordance circles are also
// repainted.
gfx::Rect damage_region = old_capture_region;
damage_region.Union(new_capture_region);
damage_region.Inset(
gfx::Insets(-kAffordanceCircleRadiusDp - kBorderStrokePx));
layer()->SchedulePaint(damage_region);
controller_->set_user_capture_region(new_capture_region);
UpdateCaptureRegionWidgets();
}
void CaptureModeSession::UpdateCaptureRegionWidgets() {
// TODO(sammiequon): The dimensons label is always shown and the capture
// button label is always shown in the fine tune stage. Update this to match
// the specs.
const bool show = controller_->source() == CaptureModeSource::kRegion;
if (!show) {
dimensions_label_widget_.reset();
capture_button_widget_.reset();
return;
}
// TODO(sammiequon): Add styling to the two widget content views. Also, the
// widgets should be repositioned if the region is too small or too close to
// the edge.
const gfx::Rect capture_region = controller_->user_capture_region();
if (!dimensions_label_widget_) {
auto* parent = GetParentContainer(current_root_);
dimensions_label_widget_ = std::make_unique<views::Widget>();
dimensions_label_widget_->Init(
CreateWidgetParams(parent, gfx::Rect(), "CaptureModeSizeLabel"));
dimensions_label_widget_->SetContentsView(std::make_unique<views::Label>());
dimensions_label_widget_->Show();
parent->StackChildBelow(dimensions_label_widget_->GetNativeWindow(),
capture_mode_bar_widget_.GetNativeWindow());
}
// Update the location of the size label. It is in the center of the region
// horizontally and slightly below the region vertically.
views::Label* size_label =
static_cast<views::Label*>(dimensions_label_widget_->GetContentsView());
size_label->SetText(base::UTF8ToUTF16(base::StringPrintf(
"%d x %d", capture_region.width(), capture_region.height())));
gfx::Rect dimensions_label_widget_bounds(size_label->GetPreferredSize());
dimensions_label_widget_bounds.set_x(capture_region.CenterPoint().x() -
dimensions_label_widget_bounds.width() /
2);
dimensions_label_widget_bounds.set_y(capture_region.bottom() +
kSizeLabelYDistanceFromRegionDp);
dimensions_label_widget_->SetBounds(dimensions_label_widget_bounds);
if (!capture_button_widget_ && !is_select_phase_) {
auto* parent = GetParentContainer(current_root_);
capture_button_widget_ = std::make_unique<views::Widget>();
capture_button_widget_->Init(
CreateWidgetParams(parent, gfx::Rect(), "CaptureModeButton"));
// TODO(sammiequon): Add the localized label.
auto label_button =
std::make_unique<views::LabelButton>(this, base::string16());
label_button->SetImage(
views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(controller_->type() == CaptureModeType::kImage
? kCaptureModeImageIcon
: kCaptureModeVideoIcon,
SK_ColorBLACK));
capture_button_widget_->SetContentsView(std::move(label_button));
capture_button_widget_->Show();
parent->StackChildBelow(capture_button_widget_->GetNativeWindow(),
capture_mode_bar_widget_.GetNativeWindow());
}
if (!capture_button_widget_)
return;
// Update the location of the capture button.
views::LabelButton* capture_button = static_cast<views::LabelButton*>(
capture_button_widget_->GetContentsView());
gfx::Rect capture_button_widget_bounds = capture_region;
capture_button_widget_bounds.ClampToCenteredSize(
capture_button->GetPreferredSize());
capture_button_widget_->SetBounds(capture_button_widget_bounds);
}
std::vector<gfx::Point> CaptureModeSession::GetAnchorPointsForPosition(
FineTunePosition position) {
std::vector<gfx::Point> anchor_points;
// For a vertex, the anchor point is the opposite vertex on the rectangle
// (ex. bottom left vertex -> top right vertex anchor point). For an edge, the
// anchor points are the two vertices of the opposite edge (ex. bottom edge ->
// top left and top right anchor points).
const gfx::Rect rect = controller_->user_capture_region();
switch (position) {
case FineTunePosition::kNone:
case FineTunePosition::kCenter:
break;
case FineTunePosition::kTopLeft:
anchor_points.push_back(rect.bottom_right());
break;
case FineTunePosition::kTopCenter:
anchor_points.push_back(rect.bottom_left());
anchor_points.push_back(rect.bottom_right());
break;
case FineTunePosition::kTopRight:
anchor_points.push_back(rect.bottom_left());
break;
case FineTunePosition::kLeftCenter:
anchor_points.push_back(rect.top_right());
anchor_points.push_back(rect.bottom_right());
break;
case FineTunePosition::kRightCenter:
anchor_points.push_back(rect.origin());
anchor_points.push_back(rect.bottom_left());
break;
case FineTunePosition::kBottomLeft:
anchor_points.push_back(rect.top_right());
break;
case FineTunePosition::kBottomCenter:
anchor_points.push_back(rect.origin());
anchor_points.push_back(rect.top_right());
break;
case FineTunePosition::kBottomRight:
anchor_points.push_back(rect.origin());
break;
}
DCHECK(!anchor_points.empty());
DCHECK_LE(anchor_points.size(), 2u);
return anchor_points;
}
} // namespace ash

@ -5,11 +5,15 @@
#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_SESSION_H_
#define ASH_CAPTURE_MODE_CAPTURE_MODE_SESSION_H_
#include <memory>
#include "ash/ash_export.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/compositor/layer_owner.h"
#include "ui/events/event.h"
#include "ui/events/event_handler.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/widget/widget.h"
namespace gfx {
@ -30,7 +34,8 @@ class CaptureModeController;
// the one that will be.
class ASH_EXPORT CaptureModeSession : public ui::LayerOwner,
public ui::LayerDelegate,
public ui::EventHandler {
public ui::EventHandler,
public views::ButtonListener {
public:
// Creates the bar widget on the given |root| window.
CaptureModeSession(CaptureModeController* controller, aura::Window* root);
@ -61,6 +66,9 @@ class ASH_EXPORT CaptureModeSession : public ui::LayerOwner,
void OnMouseEvent(ui::MouseEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
private:
// Gets the bounds of current window selected for |kWindow| capture source.
gfx::Rect GetSelectedWindowBounds() const;
@ -73,6 +81,34 @@ class ASH_EXPORT CaptureModeSession : public ui::LayerOwner,
// Paints the current capture region depending on the current capture source.
void PaintCaptureRegion(gfx::Canvas* canvas);
// Helper to unify mouse/touch events. Forwards events to the three below
// functions and they are located on |capture_button_widget_|. Blocks events
// from reaching other handlers, unless the event is located on
// |capture_mode_bar_widget_|. |is_touch| signifies this is a touch event, and
// we will use larger hit targets for the drag affordances.
void OnLocatedEvent(ui::LocatedEvent* event, bool is_touch);
// Handles updating the select region UI.
void OnLocatedEventPressed(const gfx::Point& location_in_root, bool is_touch);
void OnLocatedEventDragged(const gfx::Point& location_in_root);
void OnLocatedEventReleased(const gfx::Point& location_in_root);
// Updates the capture region and the capture region widgets.
void UpdateCaptureRegion(const gfx::Rect& new_capture_region);
// Updates the widgets that are used to display text/icons while selecting a
// capture region. They are not visible during fullscreen or window capture,
// and some are only visible during certain phases of region capture. This
// will create or destroy the widgets as needed.
void UpdateCaptureRegionWidgets();
// Retrieves the anchor points on the current selected region associated with
// |position|. The anchor points are described as the points that do not
// change when resizing the capture region while dragging one of the drag
// affordances. There is one anchor point if |position| is a vertex, and two
// anchor points if |position| is an edge.
std::vector<gfx::Point> GetAnchorPointsForPosition(FineTunePosition position);
CaptureModeController* const controller_;
// The current root window on which the capture session is active, which may
@ -84,6 +120,25 @@ class ASH_EXPORT CaptureModeSession : public ui::LayerOwner,
// The content view of the above widget and owned by its views hierarchy.
CaptureModeBarView* capture_mode_bar_view_;
// Widgets which display text and icons during a region capture session.
std::unique_ptr<views::Widget> dimensions_label_widget_;
std::unique_ptr<views::Widget> capture_button_widget_;
// Stores the data needed to select a region during a region capture session.
// There are two phases for a region capture session. The select phase, where
// the user can quickly select a region and the fine tune phase, where the
// user can reposition and resize the region with a lot of accuracy.
bool is_select_phase_ = true;
// The location of the last press and drag events.
gfx::Point initial_location_in_root_;
gfx::Point previous_location_in_root_;
// The position of the last press event during the fine tune phase drag.
FineTunePosition fine_tune_position_;
// The points that do not change during a fine tune resize. This is empty
// when |fine_tune_position_| is kNone or kCenter, or if there is no drag
// underway.
std::vector<gfx::Point> anchor_points_;
// Caches the old status of mouse warping before the session started to be
// restored at the end.
bool old_mouse_warp_status_;

@ -20,6 +20,28 @@ enum class CaptureModeSource {
kWindow,
};
// The position of the press event during the fine tune phase of a region
// capture session. This will determine what subsequent drag events do to the
// select region.
enum class FineTunePosition {
// The initial press was outside region. Subsequent drags will do nothing.
kNone,
// The initial press was inside the select region. Subsequent drags will
// move the entire region.
kCenter,
// The initial press was on one of the drag affordance circles. Subsequent
// drags will resize the region. These are sorted clockwise starting at the
// top left.
kTopLeft,
kTopCenter,
kTopRight,
kRightCenter,
kBottomRight,
kBottomCenter,
kBottomLeft,
kLeftCenter,
};
} // namespace ash
#endif // ASH_CAPTURE_MODE_CAPTURE_MODE_TYPES_H_