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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
#define UI_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
#include <array>
#include <memory>
#include <utility>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/ui_base_types.h"
#include "ui/color/color_id.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/views/input_event_activation_protector.h"
#include "ui/views/layout/delegating_layout_manager.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/dialog_observer.h"
namespace views {
class DialogDelegate;
class MdTextButton;
class Widget;
namespace features {
VIEWS_EXPORT BASE_DECLARE_FEATURE(kDialogVerticalButtonFallback);
}
// DialogClientView provides adornments for a dialog's content view, including
// custom-labeled [OK] and [Cancel] buttons with [Enter] and [Esc] accelerators.
// The view also displays the delegate's extra view alongside the buttons. The
// view appears like below. NOTE: The contents view is not inset on the top or
// side client view edges.
// +------------------------------+
// | Contents View |
// +------------------------------+
// | [Extra View] [OK] [Cancel] |
// +------------------------------+
//
// You must not directly depend on or use DialogClientView; it is internal to
// //ui/views. Access it through the public interfaces on DialogDelegate. It is
// only VIEWS_EXPORT to make it available to views_unittests.
class VIEWS_EXPORT DialogClientView : public ClientView,
public DialogObserver,
public LayoutDelegate {
METADATA_HEADER(DialogClientView, ClientView)
public:
DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kTopViewId);
DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kOkButtonElementId);
DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kCancelButtonElementId);
DialogClientView(Widget* widget, View* contents_view);
DialogClientView(const DialogClientView&) = delete;
DialogClientView& operator=(const DialogClientView&) = delete;
~DialogClientView() override;
// Accessors in case the user wishes to adjust these buttons.
MdTextButton* ok_button() const { return ok_button_; }
MdTextButton* cancel_button() const { return cancel_button_; }
View* extra_view() const { return extra_view_; }
void SetButtonRowInsets(const gfx::Insets& insets);
// View implementation:
gfx::Size CalculatePreferredSize(
const SizeBounds& available_size) const override;
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
void VisibilityChanged(View* starting_from, bool is_visible) override;
#if BUILDFLAG(IS_CHROMEOS)
// ClientView implementation:
void UpdateWindowRoundedCorners(
const gfx::RoundedCornersF& window_radii) override;
#endif // BUILDFLAG(IS_CHROMEOS)
// Input protection is triggered upon prompt creation and updated on
// visibility changes. Other situations such as top window changes in certain
// situations should trigger the input protection manually by calling this
// method. Input protection protects against certain kinds of clickjacking.
// Essentially it prevents clicks that happen within a user's double click
// interval from when the protection is started as well as any following
// clicks that happen in shorter succession than the user's double click
// interval. Refer to InputEventActivationProtector for more information. If
// `force_early` is true, force to trigger even earlier (shortly before the
// this view is visible).
void TriggerInputProtection(bool force_early = false);
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) override;
void OnThemeChanged() override;
// Update the `view_shown_time_stamp_` of input protector. A short time
// from this point onward, input event will be ignored.
void UpdateInputProtectorTimeStamp();
void set_minimum_size(const gfx::Size& size) { minimum_size_ = size; }
// Resets the time when view has been shown. Tests may need to call this
// method if they use events that could be otherwise treated as unintended.
// See IsPossiblyUnintendedInteraction().
void ResetViewShownTimeStampForTesting();
// Override the internal input protector for testing; usually to inject a mock
// version whose return value can be controlled.
void SetInputProtectorForTesting(
std::unique_ptr<views::InputEventActivationProtector> input_protector) {
input_protector_ = std::move(input_protector);
}
bool IsPossiblyUnintendedInteraction(const ui::Event& event,
bool allow_key_events);
// LayoutDelegate:
ProposedLayout CalculateProposedLayout(
const SizeBounds& size_bounds) const override;
void SetBackgroundColor(ui::ColorId background_color_id);
private:
enum {
// The number of buttons that DialogClientView can support.
kNumButtons = 3
};
class ButtonRowContainer;
// Returns the DialogDelegate for the window.
DialogDelegate* GetDialogDelegate() const;
void SetBackgroundRadii(const gfx::RoundedCornersF& radii);
void UpdateBackground();
// DialogObserver:
void OnDialogChanged() override;
// Update the dialog buttons to match the dialog's delegate.
void UpdateDialogButtons();
void OnButtonVisibilityChanged(View* view);
// Creates, deletes, or updates the appearance of the button of type `type`
// (which must be pointed to by `member`). Which action is chosen is based on
// whether DialogDelegate::GetDialogButtons() includes `type`, and whether
// `member` points to a button that already exists.
void UpdateDialogButton(raw_ptr<MdTextButton>* member,
ui::mojom::DialogButton type);
void ButtonPressed(ui::mojom::DialogButton type, const ui::Event& event);
// Returns the spacing between the extra view and the ok/cancel buttons. 0 if
// no extra view. Otherwise uses the default padding.
int GetExtraViewSpacing() const;
// Returns Views in the button row, as they should appear in the layout. If
// a View should not appear, it will be null.
std::array<View*, kNumButtons> GetButtonRowViews();
// Returns Views in column order. This is used when the buttons don't fit in
// a row, and the buttons are laid out vertically instead.
std::vector<View*> GetButtonColumnViews() const;
// Installs and configures the LayoutManager for `button_row_container_`.
void SetupLayout();
// Horizontal and vertical variations of button layout logic. The vertical
// layout is utilized if the horizontal layout exceeds a maximum width
// criteria.
void SetupHorizontalLayout();
void SetupVerticalLayout();
// Creates or deletes any buttons that are required. Updates data members.
// After calling this, no button row Views will be in the view hierarchy.
void UpdateButtonsFromModel();
// Ask the delegate for a new extra view. If there is one, replace the
// existing extra view with it.
void UpdateExtraViewFromDelegate();
// Adds/Removes a filler view depending on whether the corresponding live view
// is present.
void AddFillerView(size_t view_index);
void RemoveFillerView(size_t view_index);
// How much to inset the button row.
gfx::Insets button_row_insets_;
// The minimum size of this dialog, regardless of the size of its content
// view.
gfx::Size minimum_size_;
// The dialog buttons.
raw_ptr<MdTextButton> ok_button_ = nullptr;
raw_ptr<MdTextButton> cancel_button_ = nullptr;
// The extra view shown in the row of buttons; may be nullptr.
raw_ptr<View> extra_view_ = nullptr;
// Container view for the button row.
raw_ptr<ButtonRowContainer> button_row_container_ = nullptr;
// List of "filler" views used to keep columns in sync for TableLayout.
std::array<View*, kNumButtons> filler_views_ = {nullptr, nullptr, nullptr};
// Used to prevent unnecessary or potentially harmful changes during
// SetupLayout(). Everything will be manually updated afterwards.
bool adding_or_removing_views_ = false;
std::unique_ptr<InputEventActivationProtector> input_protector_;
ui::ColorId background_color_id_ = ui::kColorDialogBackground;
gfx::RoundedCornersF background_radii_;
};
BEGIN_VIEW_BUILDER(VIEWS_EXPORT, DialogClientView, ClientView)
END_VIEW_BUILDER
} // namespace views
DEFINE_VIEW_BUILDER(VIEWS_EXPORT, DialogClientView)
#endif // UI_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
|