1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115

ash / wm / system_panel_view.cc [blame]

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/system_panel_view.h"

#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/widget/widget.h"

namespace ash {

namespace {

// The percentage of the panel which will be used as the buffer zone around the
// screen edges.
constexpr float kBufferRatio = 2.0 / 3.0;

}  // namespace

// -----------------------------------------------------------------------------
// SystemPanelView::DragController:
void SystemPanelView::DragController::OnLocatedPanelEvent(
    views::Widget* const widget,
    ui::LocatedEvent* event) {
  if (!widget) {
    is_dragging_ = false;
    base::debug::DumpWithoutCrashing();
    return;
  }

  switch (event->type()) {
    case ui::EventType::kMousePressed:
    case ui::EventType::kGestureScrollBegin:
      is_dragging_ = true;
      panel_widget_initial_bounds_ = widget->GetWindowBoundsInScreen();
      start_dragging_event_location_ =
          event->target()->GetScreenLocation(*event);
      event->SetHandled();
      break;
    case ui::EventType::kMouseDragged:
    case ui::EventType::kGestureScrollUpdate: {
      if (!is_dragging_) {
        break;
      }

      gfx::Point event_location = event->target()->GetScreenLocation(*event);
      gfx::Rect panel_widget_bounds = panel_widget_initial_bounds_;
      panel_widget_bounds.Offset(event_location -
                                 start_dragging_event_location_);

      // Establishes a buffer zone around the screen edges equal to
      // `kBufferRatio` of the height or width of the panel. This will prevent
      // the panel from being dragged too far that less than 1-`kBufferRatio` of
      // it remains visible on the screen.
      auto buff_width = panel_widget_bounds.width() * kBufferRatio;
      auto buff_height = panel_widget_bounds.height() * kBufferRatio;
      auto screen_bounds = display::Screen::GetScreen()
                               ->GetDisplayNearestPoint(event_location)
                               .bounds();
      screen_bounds.SetByBounds(
          screen_bounds.x() - buff_width, screen_bounds.y() - buff_height,
          screen_bounds.width() + screen_bounds.x() + buff_width,
          screen_bounds.y() + screen_bounds.height() + buff_height);
      panel_widget_bounds.AdjustToFit(screen_bounds);

      widget->SetBounds(panel_widget_bounds);
      event->SetHandled();
      break;
    }
    case ui::EventType::kMouseReleased:
    case ui::EventType::kGestureScrollEnd:
    case ui::EventType::kGestureEnd:
      if (!is_dragging_) {
        break;
      }
      is_dragging_ = false;
      event->SetHandled();
      break;
    default:
      break;
  }
}

// -----------------------------------------------------------------------------
// SystemPanelView:

SystemPanelView::SystemPanelView() = default;

SystemPanelView::~SystemPanelView() = default;

void SystemPanelView::OnMouseEvent(ui::MouseEvent* event) {
  HandleDragEventIfNeeded(event);
}

void SystemPanelView::OnGestureEvent(ui::GestureEvent* event) {
  HandleDragEventIfNeeded(event);
}

void SystemPanelView::HandleDragEventIfNeeded(ui::LocatedEvent* event) {
  // Checks whether the event is part of a drag sequence and handles it if
  // needed. Note that we only handle drag events for repositioning the panel
  // here. Other drag behavior, e.g. for text selection, is handled by the
  // panel's child views.
  drag_controller_.OnLocatedPanelEvent(GetWidget(), event);
}

BEGIN_METADATA(SystemPanelView)
END_METADATA

}  // namespace ash