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
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136

ash / shelf / desk_button_widget.h [blame]

// 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_SHELF_DESK_BUTTON_WIDGET_H_
#define ASH_SHELF_DESK_BUTTON_WIDGET_H_

#include "ash/ash_export.h"
#include "ash/shelf/shelf_component.h"
#include "base/memory/raw_ptr.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"

namespace ash {

class DeskButtonContainer;
class Shelf;
enum class ShelfAlignment;

// The desk button provides an overview of existing desks and quick access to
// them. The button is only visible in clamshell mode and disappears when in
// overview.
class ASH_EXPORT DeskButtonWidget : public ShelfComponent,
                                    public views::Widget {
 public:
  // Delegate view for laying out the desk button UI. It does not use the
  // default fill layout since the desk button UI has dynamic size, and the
  // widget reserves the maximum possible space for the current shelf alignment
  // and zero state.
  class DelegateView : public views::WidgetDelegateView {
   public:
    DelegateView();
    DelegateView(const DelegateView&) = delete;
    DelegateView& operator=(const DelegateView&) = delete;
    ~DelegateView() override;

    DeskButtonContainer* desk_button_container() const {
      return desk_button_container_;
    }

    // Initializes the view. Must be called before any meaningful UIs can be
    // laid out.
    void Init(DeskButtonWidget* desk_button_widget);

    // views::WidgetDelegateView:
    bool CanActivate() const override;
    void Layout(PassKey) override;

    // views::View:
    bool AcceleratorPressed(const ui::Accelerator& accelerator) override;

   private:
    raw_ptr<DeskButtonContainer> desk_button_container_ = nullptr;
    raw_ptr<DeskButtonWidget> desk_button_widget_ = nullptr;
  };

  explicit DeskButtonWidget(Shelf* shelf);
  DeskButtonWidget(const DeskButtonWidget&) = delete;
  DeskButtonWidget& operator=(const DeskButtonWidget&) = delete;
  ~DeskButtonWidget() override;

  // Returns the max length for the widget for the horizontal or vertical shelf.
  static int GetMaxLength(bool horizontal_shelf);

  DelegateView* delegate_view() const { return delegate_view_; }

  Shelf* shelf() const { return shelf_; }

  // Indicates if the shelf should reserve some space for this widget.
  bool ShouldReserveSpaceFromShelf() const;

  // Whether the desk button should currently be visible.
  bool ShouldBeVisible() const;

  // Updates expanded state and values impacted by shelf alignment change.
  void PrepareForAlignmentChange();

  // ShelfComponent:
  void CalculateTargetBounds() override;
  gfx::Rect GetTargetBounds() const override;
  void UpdateLayout(bool animate) override;
  void UpdateTargetBoundsForGesture(int shelf_position) override;

  // Called when shelf layout manager detects a locale change.
  void HandleLocaleChange();

  // Initializes the widget, sets its contents view and basic properties.
  void Initialize(aura::Window* container);

  DeskButtonContainer* GetDeskButtonContainer() const;

  // Returns true if this widget belongs to a horizontal shelf.
  bool IsHorizontalShelf() const;

  void SetDefaultChildToFocus(views::View* default_child_to_focus);

  // Stores the current focused view for desk button widget.
  void StoreDeskButtonFocus();

  // Restores focus to the stored focused view of desk button widget if there is
  // one.
  void RestoreDeskButtonFocus();

  // Depending on what child view has focus, either focus out of the desk
  // button, or pass the focus to the next view. `reverse` indicates backward
  // focusing, otherwise forward focusing.
  void MaybeFocusOut(bool reverse);

  // Sets previous focus and next focus of desk button.
  void InitializeAccessibleProperties();

 private:
  // views::Widget:
  bool OnNativeWidgetActivationChanged(bool active) override;

  raw_ptr<DelegateView, DanglingUntriaged> delegate_view_ = nullptr;

  gfx::Rect target_bounds_;

  raw_ptr<Shelf> const shelf_;

  // Default child view to focus when `OnNativeWidgetActivationChanged()`
  // occurs. When it's not null, it should point to the desk button, the
  // previous desk button, or the next desk button.
  raw_ptr<views::View> default_child_to_focus_ = nullptr;

  // Stored focused view for the widget. This is used to restore the focus to
  // the desk button when the desk bar is closed. When it's not null, it should
  // point to the desk button, the previous desk button, or the next desk
  // button.
  raw_ptr<views::View> stored_focused_view_ = nullptr;
};

}  // namespace ash

#endif  // ASH_SHELF_DESK_BUTTON_WIDGET_H_