chromium/ash/system/toast/anchored_nudge.h

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

#ifndef ASH_SYSTEM_TOAST_ANCHORED_NUDGE_H_
#define ASH_SYSTEM_TOAST_ANCHORED_NUDGE_H_

#include <string>

#include "ash/ash_export.h"
#include "ash/public/cpp/system/anchored_nudge_data.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_observer.h"
#include "ash/shell_observer.h"
#include "base/functional/callback_forward.h"
#include "base/scoped_observation.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/display/display_observer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/widget/widget_observer.h"

namespace views {
class Widget;
}  // namespace views

namespace ui {
class GestureEvent;
class MouseEvent;
}  // namespace ui

namespace aura {
class Window;
}

namespace ash {

class SystemNudgeView;

// Creates and manages the widget and contents view for an anchored nudge.
// TODO(b/285988235): `AnchoredNudge` will replace the existing `SystemNudge`
// and take over its name.
class ASH_EXPORT AnchoredNudge : public display::DisplayObserver,
                                 public ShelfObserver,
                                 public ShellObserver,
                                 public views::BubbleDialogDelegateView,
                                 public views::WidgetObserver {
  METADATA_HEADER(AnchoredNudge, views::BubbleDialogDelegateView)

 public:
  AnchoredNudge(AnchoredNudgeData& nudge_data,
                base::RepeatingCallback<void(/*has_hover_or_focus=*/bool)>
                    hover_or_focus_changed_callback);
  AnchoredNudge(const AnchoredNudge&) = delete;
  AnchoredNudge& operator=(const AnchoredNudge&) = delete;
  ~AnchoredNudge() override;

  // views::BubbleDialogDelegateView:
  gfx::Rect GetBubbleBounds() override;
  void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
                                views::Widget* widget) const override;

  // views::WidgetDelegate:
  std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
      views::Widget* widget) override;

  // views::View:
  void AddedToWidget() override;
  bool OnMousePressed(const ui::MouseEvent& event) override;
  bool OnMouseDragged(const ui::MouseEvent& event) override;
  void OnMouseReleased(const ui::MouseEvent& event) override;
  void OnGestureEvent(ui::GestureEvent* event) override;

  // ShelfObserver:
  void OnAutoHideStateChanged(ShelfAutoHideState new_state) override;
  void OnHotseatStateChanged(HotseatState old_state,
                             HotseatState new_state) override;

  // ShellObserver:
  void OnShelfAlignmentChanged(aura::Window* root_window,
                               ShelfAlignment old_alignment) override;

  // display::DisplayObserver:
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

  // views::WidgetObserver:
  void OnWidgetDestroying(views::Widget* widget) override;
  void OnWidgetBoundsChanged(views::Widget* widget,
                             const gfx::Rect& new_bounds) override;

  // Sets the arrow of the nudge based on the `shelf` alignment.
  void SetArrowFromShelf(Shelf* shelf);

  // Sets the default anchor rect for nudges that do not have an `anchor_view`.
  void SetDefaultAnchorRect();

  const std::string& id() const { return id_; }

  NudgeCatalogName catalog_name() const { return catalog_name_; }

 private:
  // Unique id used to find and dismiss the nudge through the manager.
  const std::string id_;

  // Used to identify nudges that share an id but have different catalog names.
  const NudgeCatalogName catalog_name_;

  // Whether the nudge should set its arrow based on shelf alignment.
  const bool anchored_to_shelf_;

  // Whether the nudge should set its bounds anchored by its corners.
  const bool is_corner_anchored_;

  // Whether the nudge should set its parent as the `anchor_view`.
  const bool set_anchor_view_as_parent_ = false;

  // If not null, the nudge will anchor to one of the anchor widget internal
  // corners. Currently only supports anchoring to the bottom corners.
  raw_ptr<views::Widget> anchor_widget_ = nullptr;

  // The corner of the `anchor_widget_` to which the nudge will anchor.
  views::BubbleBorder::Arrow anchor_widget_corner_ =
      views::BubbleBorder::Arrow::BOTTOM_LEFT;

  // Owned by the views hierarchy. Contents view of the anchored nudge.
  raw_ptr<SystemNudgeView> system_nudge_view_ = nullptr;

  // Nudge action callbacks.
  NudgeClickCallback click_callback_;
  NudgeDismissCallback dismiss_callback_;

  // Used to maintain the shelf visible while a shelf-anchored nudge is shown.
  std::unique_ptr<Shelf::ScopedDisableAutoHide> disable_shelf_auto_hide_;

  base::ScopedObservation<views::Widget, views::WidgetObserver>
      anchor_widget_scoped_observation_{this};

  // Used to observe hotseat state to update nudges default location baseline.
  base::ScopedObservation<Shelf, ShelfObserver> shelf_observation_{this};

  // Observes display configuration changes.
  display::ScopedDisplayObserver display_observer_{this};
};

}  // namespace ash

#endif  // ASH_SYSTEM_TOAST_ANCHORED_NUDGE_H_