chromium/ash/wm/window_mini_view.h

// Copyright 2019 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_WM_WINDOW_MINI_VIEW_H_
#define ASH_WM_WINDOW_MINI_VIEW_H_

#include "ash/ash_export.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "ui/aura/window_observer.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/views/view.h"

namespace aura {
class Window;
}  // namespace aura

namespace gfx {
class Point;
}  // namespace gfx

namespace views {
class HighlightPathGenerator;
}  // namespace views

namespace ash {
class WindowMiniViewHeaderView;
class WindowPreviewView;

// Defines the interface that extracts the window, visual updates, focus
// installation and update logic to be used or implemented by `WindowMiniView`
// and `GroupContainerCycleView`.
class WindowMiniViewBase : public views::View {
  METADATA_HEADER(WindowMiniViewBase, views::View)

 public:
  WindowMiniViewBase(const WindowMiniViewBase&) = delete;
  WindowMiniViewBase& operator=(const WindowMiniViewBase&) = delete;
  ~WindowMiniViewBase() override;

  bool is_mini_view_focused() const { return is_focused_; }

  // Shows or hides a focus ring around this.
  void UpdateFocusState(bool focus);

  // Returns true if a preview of the given `window` is contained in `this`.
  virtual bool Contains(aura::Window* window) const = 0;

  // If `screen_point` is within the screen bounds of a preview view inside
  // this, returns the window represented by this view, nullptr otherwise.
  virtual aura::Window* GetWindowAtPoint(
      const gfx::Point& screen_point) const = 0;

  // Creates or deletes preview view as needed. For performance reasons, these
  // are not created on construction. Note that this may create or destroy a
  // `WindowPreviewView` which is an expensive operation.
  virtual void SetShowPreview(bool show) = 0;

  // Refreshes the rounded corners and optionally updates the icon view.
  virtual void RefreshItemVisuals() = 0;

  // Try removing the mini view representation of the `destroying_window`.
  // Returns the number of remaining child items that represent windows within
  // `this`. Returns 0, if `destroying_window` is represented by `this` itself
  // rather than a child item.
  virtual int TryRemovingChildItem(aura::Window* destroying_window) = 0;

  // Returns the exposed rounded corners.
  virtual gfx::RoundedCornersF GetRoundedCorners() const = 0;

  // Sets `this` as selected for focus and applies the focus ring around it.
  // Note that `window` is the window that will be activated if `this` is
  // selected while focused. `window` must be contained within `this` (See
  // `Contains()` above).
  virtual void SetSelectedWindowForFocus(aura::Window* window) = 0;

  // Clears the focus on all the windows associated with `this`.
  virtual void ClearFocusSelection() = 0;

 protected:
  WindowMiniViewBase();

  // True if `this` is focused when using keyboard navigation.
  bool is_focused_ = false;
};

// WindowMiniView is a view which contains a header and optionally a mirror of
// the given window. Displaying the mirror is chosen by the subclass by calling
// `SetShowPreview` in their constructors (or later on if they like).
class ASH_EXPORT WindowMiniView : public WindowMiniViewBase,
                                  public aura::WindowObserver {
  METADATA_HEADER(WindowMiniView, WindowMiniViewBase)

 public:
  WindowMiniView(const WindowMiniView&) = delete;
  WindowMiniView& operator=(const WindowMiniView&) = delete;
  ~WindowMiniView() override;

  // The size in dp of the window icon shown on the alt-tab/overview window next
  // to the title.
  static constexpr gfx::Size kIconSize = gfx::Size(24, 24);

  aura::Window* source_window() { return source_window_; }
  const aura::Window* source_window() const { return source_window_; }
  WindowMiniViewHeaderView* header_view() { return header_view_; }
  views::View* backdrop_view() { return backdrop_view_; }
  WindowPreviewView* preview_view() { return preview_view_; }
  const WindowPreviewView* preview_view() const { return preview_view_; }

  // Sets rounded corners on the exposed corners, the inner corners will be
  // sharp.
  void SetRoundedCornersRadius(
      const gfx::RoundedCornersF& exposed_rounded_corners);

  // Sets the visibility of |backdrop_view_|. Creates it if it is null.
  void SetBackdropVisibility(bool visible);

  // Sets or hides rounded corners on `preview_view_`, if it exists.
  void RefreshPreviewRoundedCorners();

  // Updates the rounded corners on `header_view_`, if it exists.
  void RefreshHeaderViewRoundedCorners();

  // Applies the corresponding rounded corners on the focus ring to match the
  // visuals of the `header_view_` and `preview_view_`.
  void RefreshFocusRingVisuals();

  // Resets the preset rounded corners values i.e.
  // `header_view_rounded_corners_` and `preview_view_rounded_corners_`.
  void ResetRoundedCorners();

  // WindowMiniViewBase:
  bool Contains(aura::Window* window) const override;
  aura::Window* GetWindowAtPoint(const gfx::Point& screen_point) const override;
  void SetShowPreview(bool show) override;
  int TryRemovingChildItem(aura::Window* destroying_window) override;
  gfx::RoundedCornersF GetRoundedCorners() const override;
  void SetSelectedWindowForFocus(aura::Window* window) override;
  void ClearFocusSelection() override;
  void Layout(PassKey) override;

  // aura::WindowObserver:
  void OnWindowPropertyChanged(aura::Window* window,
                               const void* key,
                               intptr_t old) override;
  void OnWindowDestroying(aura::Window* window) override;
  void OnWindowTitleChanged(aura::Window* window) override;

 protected:
  WindowMiniView(aura::Window* source_window, bool use_custom_focus_predicate);

  // Returns the bounds where the backdrop and preview should go.
  gfx::Rect GetContentAreaBounds() const;

  gfx::Rect GetHeaderBounds() const;

  // Subclasses can override this function to provide customization for margins
  // and layouts of the preview view.
  virtual gfx::Size GetPreviewViewSize() const;

 private:
  // Called when setting the rounded corners to refresh the rounded corners on
  // the `header_view_`, `preview_view_` and focus ring.
  void OnRoundedCornersSet();

  void InstallFocusRing(bool use_custom_predicate);

  void UpdateAccessibleIgnoredState();
  void UpdateAccessibleName();

  // Generates the focus ring path for `this`, which has four rounded corners by
  // default. If this is part of a snap group, the path should match the rounded
  // corners of the `this`.
  std::unique_ptr<views::HighlightPathGenerator> GenerateFocusRingPath();

  // The window this class is meant to be a header for. This class also may
  // optionally show a mirrored view of this window.
  raw_ptr<aura::Window> source_window_;

  // A view that represents the header of `this`.
  raw_ptr<WindowMiniViewHeaderView> header_view_ = nullptr;

  // A view that covers the area except the header. It is null when the window
  // associated is not pillar or letter boxed.
  raw_ptr<views::View> backdrop_view_ = nullptr;

  // Optionally shows a preview of |window_|.
  raw_ptr<WindowPreviewView, DanglingUntriaged> preview_view_ = nullptr;

  // If these optional values are set, they will be used otherwise the default
  // rounded corners will be used.
  std::optional<gfx::RoundedCornersF> exposed_rounded_corners_;
  std::optional<gfx::RoundedCornersF> preview_view_rounded_corners_;

  base::ScopedObservation<aura::Window, aura::WindowObserver>
      window_observation_{this};
};

}  // namespace ash

#endif  // ASH_WM_WINDOW_MINI_VIEW_H_