chromium/ash/components/arc/compat_mode/resize_toggle_menu.h

// Copyright 2021 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_COMPONENTS_ARC_COMPAT_MODE_RESIZE_TOGGLE_MENU_H_
#define ASH_COMPONENTS_ARC_COMPAT_MODE_RESIZE_TOGGLE_MENU_H_

#include <memory>

#include "ash/components/arc/compat_mode/resize_util.h"
#include "base/cancelable_callback.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/scoped_multi_source_observation.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"

namespace gfx {
class Rect;
struct VectorIcon;
}  // namespace gfx

namespace views {
class BubbleDialogDelegateView;
class ImageView;
class Label;
}  // namespace views

namespace arc {

class ArcResizeLockPrefDelegate;

class ResizeToggleMenu : public views::WidgetObserver,
                         public aura::WindowObserver {
 public:
  class MenuButtonView : public views::Button {
    METADATA_HEADER(MenuButtonView, views::Button)

   public:
    MenuButtonView(PressedCallback callback,
                   const gfx::VectorIcon& icon,
                   int title_string_id);
    MenuButtonView(const MenuButtonView&) = delete;
    MenuButtonView& operator=(const MenuButtonView&) = delete;
    ~MenuButtonView() override;

    void SetSelected(bool is_selected);

   private:
    // views::View:
    void OnThemeChanged() override;
    gfx::Size CalculatePreferredSize(
        const views::SizeBounds& available_size) const override;

    void UpdateColors();
    void UpdateState();

    // Owned by views hierarchy.
    raw_ptr<views::ImageView> icon_view_{nullptr};
    raw_ptr<views::Label> title_{nullptr};

    const raw_ref<const gfx::VectorIcon> icon_;
    bool is_selected_{false};
    const int title_string_id_;
  };

  ResizeToggleMenu(base::OnceClosure on_bubble_widget_closing_callback,
                   views::Widget* widget,
                   ArcResizeLockPrefDelegate* pref_delegate);
  ResizeToggleMenu(const ResizeToggleMenu&) = delete;
  ResizeToggleMenu& operator=(const ResizeToggleMenu&) = delete;
  ~ResizeToggleMenu() override;

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

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

  bool IsBubbleShown() const;

 private:
  friend class ResizeToggleMenuTest;

  void UpdateSelectedButton();

  void ApplyResizeCompatMode(ash::ResizeCompatMode mode);

  gfx::Rect GetAnchorRect() const;

  base::WeakPtr<views::BubbleDialogDelegateView> bubble_view_;

  std::unique_ptr<views::BubbleDialogDelegateView> MakeBubbleDelegateView(
      views::Widget* parent,
      gfx::Rect anchor_rect,
      base::RepeatingCallback<void(ash::ResizeCompatMode)> command_handler);

  void CloseBubble();

  base::OnceClosure on_bubble_widget_closing_callback_;

  raw_ptr<views::Widget> widget_;

  raw_ptr<ArcResizeLockPrefDelegate> pref_delegate_;

  base::ScopedMultiSourceObservation<views::Widget, views::WidgetObserver>
      widget_observations_{this};
  base::ScopedObservation<aura::Window, aura::WindowObserver>
      window_observation_{this};

  base::CancelableOnceClosure auto_close_closure_;

  raw_ptr<views::Widget> bubble_widget_{nullptr};

  // Store only for testing.
  raw_ptr<MenuButtonView, DanglingUntriaged> phone_button_{nullptr};
  raw_ptr<MenuButtonView, DanglingUntriaged> tablet_button_{nullptr};
  raw_ptr<MenuButtonView, DanglingUntriaged> resizable_button_{nullptr};

  base::WeakPtrFactory<ResizeToggleMenu> weak_ptr_factory_{this};
};

}  // namespace arc

#endif  // ASH_COMPONENTS_ARC_COMPAT_MODE_RESIZE_TOGGLE_MENU_H_