#ifndef ASH_WM_SCOPED_WINDOW_TUCKER_H_
#define ASH_WM_SCOPED_WINDOW_TUCKER_H_
#include <memory>
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/window_state.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/aura/scoped_window_event_targeting_blocker.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/widget/unique_widget_ptr.h"
#include "ui/wm/public/activation_change_observer.h"
namespace ash {
constexpr char kTuckUserAction[] = "FloatWindowTucked";
constexpr char kUntuckUserAction[] = "FloatWindowUntucked";
class ScopedWindowTucker : public wm::ActivationChangeObserver,
public OverviewObserver,
public aura::WindowObserver {
public:
static constexpr int kTuckHandleWidth = 20;
static constexpr int kTuckHandleHeight = 92;
class Delegate {
public:
Delegate();
virtual ~Delegate();
virtual void PaintTuckHandle(gfx::Canvas* canvas, int width, bool left) = 0;
virtual int ParentContainerId() const = 0;
virtual void UpdateWindowPosition(aura::Window* window, bool left) = 0;
virtual void UntuckWindow(aura::Window* window) = 0;
virtual void OnAnimateTuckEnded(aura::Window* window) = 0;
virtual gfx::Rect GetTuckHandleBounds(
bool left,
const gfx::Rect& window_bounds) const = 0;
base::WeakPtr<Delegate> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
base::WeakPtrFactory<Delegate> weak_ptr_factory_{this};
};
class TuckHandleView : public views::Button,
public views::ViewTargeterDelegate {
public:
TuckHandleView(base::WeakPtr<Delegate> delegate,
base::RepeatingClosure callback,
bool left);
TuckHandleView(const TuckHandleView&) = delete;
TuckHandleView& operator=(const TuckHandleView&) = delete;
~TuckHandleView() override;
void OnThemeChanged() override;
void PaintButtonContents(gfx::Canvas* canvas) override;
void OnGestureEvent(ui::GestureEvent* event) override;
bool DoesIntersectRect(const views::View* target,
const gfx::Rect& rect) const override;
private:
base::WeakPtr<Delegate> scoped_window_tucker_delegate_;
const bool left_;
};
explicit ScopedWindowTucker(std::unique_ptr<Delegate> delegate,
aura::Window* window,
bool left);
ScopedWindowTucker(const ScopedWindowTucker&) = delete;
ScopedWindowTucker& operator=(const ScopedWindowTucker&) = delete;
~ScopedWindowTucker() override;
aura::Window* window() { return window_; }
views::Widget* tuck_handle_widget() { return tuck_handle_widget_.get(); }
bool left() const { return left_; }
void AnimateTuck();
void AnimateUntuck(base::OnceClosure callback);
void UntuckWindow();
void OnAnimateTuckEnded();
void OnWindowActivated(ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
void OnOverviewModeStarting() override;
void OnOverviewModeEndingAnimationComplete(bool canceled) override;
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
private:
void InitializeTuckHandleWidget();
void OnOverviewModeChanged(bool in_overview);
std::unique_ptr<Delegate> delegate_;
raw_ptr<aura::Window> window_;
bool left_ = false;
aura::ScopedWindowEventTargetingBlocker event_blocker_;
views::UniqueWidgetPtr tuck_handle_widget_ =
std::make_unique<views::Widget>();
base::ScopedObservation<OverviewController, OverviewObserver>
overview_observer_{this};
base::ScopedObservation<aura::Window, aura::WindowObserver>
window_observation_{this};
base::WeakPtrFactory<ScopedWindowTucker> weak_factory_{this};
};
}
#endif