blob: 42bd8f95ce90bb7f4777f8ff12142f42484bec68 [file] [log] [blame]
Avi Drissman3a215d1e2022-09-07 19:43:091// Copyright 2018 The Chromium Authors
Manu Corneta6cf9b4f2018-06-26 22:00:312// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/shelf/window_preview.h"
6
Matthew Mourgos75327562019-09-09 21:23:577#include "ash/public/cpp/shelf_config.h"
Manu Corneta6cf9b4f2018-06-26 22:00:318#include "ash/resources/vector_icons/vector_icons.h"
Sammie Quonb2223fc2018-12-06 01:34:529#include "ash/wm/window_preview_view.h"
Manu Corneta6cf9b4f2018-06-26 22:00:3110#include "ash/wm/window_util.h"
Avi Drissman4de6dab2023-01-06 23:17:3511#include "base/functional/bind.h"
Manu Corneta6cf9b4f2018-06-26 22:00:3112#include "ui/aura/window.h"
Peter Kastingc63c9932021-09-27 15:36:0013#include "ui/color/color_id.h"
14#include "ui/color/color_provider.h"
Manu Cornet899520932019-04-03 04:59:2715#include "ui/gfx/color_palette.h"
Manu Corneta6cf9b4f2018-06-26 22:00:3116#include "ui/gfx/paint_vector_icon.h"
Manu Cornet899520932019-04-03 04:59:2717#include "ui/views/background.h"
Manu Corneta6cf9b4f2018-06-26 22:00:3118#include "ui/views/controls/button/image_button.h"
19#include "ui/views/controls/label.h"
20
21namespace ash {
22
Manu Corneta6cf9b4f2018-06-26 22:00:3123// The margins around window titles.
24constexpr int kTitleLineHeight = 20;
25constexpr int kTitleMarginTop = 10;
26constexpr int kTitleMarginBottom = 10;
27constexpr int kTitleMarginRight = 16;
28
29// The width and height of close buttons.
30constexpr int kCloseButtonSize = 36;
31constexpr int kCloseButtonImageSize = 24;
32constexpr int kCloseButtonSideBleed = 8;
33constexpr SkColor kCloseButtonColor = SK_ColorWHITE;
34
Manu Cornet899520932019-04-03 04:59:2735constexpr SkColor kPreviewContainerBgColor =
36 SkColorSetA(gfx::kGoogleGrey100, 0x24);
37constexpr int kPreviewBorderRadius = 4;
38
Peter Kastingc63c9932021-09-27 15:36:0039WindowPreview::WindowPreview(aura::Window* window, Delegate* delegate)
Manu Corneta6cf9b4f2018-06-26 22:00:3140 : delegate_(delegate) {
Sammie Quonb2223fc2018-12-06 01:34:5241 preview_view_ =
James Cook00e65e92019-07-25 03:19:0842 new WindowPreviewView(window, /*trilinear_filtering_on_init=*/false);
Manu Cornet899520932019-04-03 04:59:2743 preview_container_view_ = new views::View();
44 preview_container_view_->SetBackground(views::CreateRoundedRectBackground(
45 kPreviewContainerBgColor, kPreviewBorderRadius));
Manu Corneta6cf9b4f2018-06-26 22:00:3146 title_ = new views::Label(window->GetTitle());
Peter Kasting67718122020-11-03 07:54:0447 close_button_ = new views::ImageButton(base::BindRepeating(
48 &WindowPreview::CloseButtonPressed, base::Unretained(this)));
Sophie Wena4c4b8f2022-06-21 18:19:3849 close_button_->SetFocusBehavior(FocusBehavior::NEVER);
Manu Corneta6cf9b4f2018-06-26 22:00:3150
Arthur Sonzogni834e018f2023-04-22 10:20:0251 AddChildView(preview_container_view_.get());
52 AddChildView(preview_view_.get());
53 AddChildView(title_.get());
54 AddChildView(close_button_.get());
Manu Corneta6cf9b4f2018-06-26 22:00:3155}
56
57WindowPreview::~WindowPreview() = default;
58
Manu Corneta6cf9b4f2018-06-26 22:00:3159gfx::Size WindowPreview::CalculatePreferredSize() const {
Manu Cornet899520932019-04-03 04:59:2760 // The preview itself will always be strictly contained within its container,
61 // so only the container's size matters to calculate the preferred size.
62 const gfx::Size container_size = GetPreviewContainerSize();
63 const int title_height_with_padding =
Manu Corneta6cf9b4f2018-06-26 22:00:3164 kTitleLineHeight + kTitleMarginTop + kTitleMarginBottom;
Manu Cornet899520932019-04-03 04:59:2765 return gfx::Size(container_size.width(),
66 container_size.height() + title_height_with_padding);
Manu Corneta6cf9b4f2018-06-26 22:00:3167}
68
69void WindowPreview::Layout() {
70 gfx::Rect content_rect = GetContentsBounds();
Manu Corneta6cf9b4f2018-06-26 22:00:3171
72 gfx::Size title_size = title_->CalculatePreferredSize();
73 int title_height_with_padding =
74 kTitleLineHeight + kTitleMarginTop + kTitleMarginBottom;
Manu Cornet899520932019-04-03 04:59:2775 int title_width =
76 std::min(title_size.width(),
77 content_rect.width() - kCloseButtonSize - kTitleMarginRight);
Manu Corneta6cf9b4f2018-06-26 22:00:3178 title_->SetBoundsRect(gfx::Rect(content_rect.x(),
79 content_rect.y() + kTitleMarginTop,
80 title_width, kTitleLineHeight));
Manu Cornet899520932019-04-03 04:59:2781
Manu Corneta6cf9b4f2018-06-26 22:00:3182 close_button_->SetBoundsRect(
83 gfx::Rect(content_rect.right() - kCloseButtonSize + kCloseButtonSideBleed,
84 content_rect.y(), kCloseButtonSize, kCloseButtonSize));
Manu Cornet899520932019-04-03 04:59:2785
86 const gfx::Size container_size = GetPreviewContainerSize();
87 gfx::Size mirror_size = preview_view_->CalculatePreferredSize();
88 float preview_ratio = static_cast<float>(mirror_size.width()) /
89 static_cast<float>(mirror_size.height());
90
Matthew Mourgos75327562019-09-09 21:23:5791 int preview_height = ShelfConfig::Get()->shelf_tooltip_preview_height();
Manu Cornet899520932019-04-03 04:59:2792 int preview_width = preview_height * preview_ratio;
Matthew Mourgos75327562019-09-09 21:23:5793 if (preview_ratio > ShelfConfig::Get()->shelf_tooltip_preview_max_ratio()) {
Manu Cornet899520932019-04-03 04:59:2794 // Very wide window.
Matthew Mourgos75327562019-09-09 21:23:5795 preview_width = ShelfConfig::Get()->shelf_tooltip_preview_max_width();
96 preview_height =
97 ShelfConfig::Get()->shelf_tooltip_preview_max_width() / preview_ratio;
Manu Cornet899520932019-04-03 04:59:2798 }
99
100 // Center the actual preview over the container, horizontally and vertically.
101 gfx::Point preview_offset_from_container(
102 (container_size.width() - preview_width) / 2,
103 (container_size.height() - preview_height) / 2);
104
105 const int preview_container_top =
106 content_rect.y() + title_height_with_padding;
107 preview_container_view_->SetBoundsRect(
108 gfx::Rect(content_rect.x(), preview_container_top, container_size.width(),
109 container_size.height()));
Sammie Quonb2223fc2018-12-06 01:34:52110 preview_view_->SetBoundsRect(
Manu Cornet899520932019-04-03 04:59:27111 gfx::Rect(content_rect.x() + preview_offset_from_container.x(),
112 preview_container_top + preview_offset_from_container.y(),
113 preview_width, preview_height));
Manu Corneta6cf9b4f2018-06-26 22:00:31114}
115
116bool WindowPreview::OnMousePressed(const ui::MouseEvent& event) {
Sammie Quonb2223fc2018-12-06 01:34:52117 if (!preview_view_->bounds().Contains(event.location()))
Manu Corneta6cf9b4f2018-06-26 22:00:31118 return false;
119
Sammie Quonb2223fc2018-12-06 01:34:52120 aura::Window* target = preview_view_->window();
121 if (target) {
Manu Corneta6cf9b4f2018-06-26 22:00:31122 // The window might have been closed in the mean time.
123 // TODO: Use WindowObserver to listen to when previewed windows are
124 // being closed and remove this condition.
Sammie Quonb2223fc2018-12-06 01:34:52125 wm::ActivateWindow(target);
Manu Corneta6cf9b4f2018-06-26 22:00:31126
127 // This will have the effect of deleting this view.
128 delegate_->OnPreviewActivated(this);
129 }
130 return true;
131}
132
Andrew Lee4c6dc1942019-05-30 00:18:35133const char* WindowPreview::GetClassName() const {
134 return "WindowPreview";
135}
136
Peter Kastingc63c9932021-09-27 15:36:00137void WindowPreview::OnThemeChanged() {
Sophie Wena4c4b8f2022-06-21 18:19:38138 views::View::OnThemeChanged();
Peter Kastingc63c9932021-09-27 15:36:00139 const auto* color_provider = GetColorProvider();
Manu Cornet899520932019-04-03 04:59:27140 SkColor background_color =
Peter Kastingc63c9932021-09-27 15:36:00141 color_provider->GetColor(ui::kColorTooltipBackground);
Manu Cornet899520932019-04-03 04:59:27142 title_->SetEnabledColor(
Peter Kastingc63c9932021-09-27 15:36:00143 color_provider->GetColor(ui::kColorTooltipForeground));
Manu Cornet899520932019-04-03 04:59:27144 title_->SetBackgroundColor(background_color);
145
146 // The background is not opaque, so we can't do subpixel rendering.
147 title_->SetSubpixelRenderingEnabled(false);
148
149 close_button_->SetImage(
150 views::Button::STATE_NORMAL,
151 gfx::CreateVectorIcon(kOverviewWindowCloseIcon, kCloseButtonColor));
Peter Kasting4978eacb2019-05-15 18:36:10152 close_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
153 close_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
Manu Cornet899520932019-04-03 04:59:27154 close_button_->SetMinimumImageSize(
155 gfx::Size(kCloseButtonImageSize, kCloseButtonImageSize));
156}
157
158gfx::Size WindowPreview::GetPreviewContainerSize() const {
159 return gfx::Size(
Matthew Mourgos75327562019-09-09 21:23:57160 std::min(delegate_->GetMaxPreviewRatio() *
161 ShelfConfig::Get()->shelf_tooltip_preview_height(),
162 static_cast<float>(
163 ShelfConfig::Get()->shelf_tooltip_preview_max_width())),
164 ShelfConfig::Get()->shelf_tooltip_preview_height());
Manu Cornet899520932019-04-03 04:59:27165}
166
Peter Kasting67718122020-11-03 07:54:04167void WindowPreview::CloseButtonPressed() {
168 // The window might have been closed in the mean time.
169 // TODO: Use WindowObserver to listen to when previewed windows are
170 // being closed and remove this condition.
171 aura::Window* target = preview_view_->window();
172 if (!target)
173 return;
174 window_util::CloseWidgetForWindow(target);
175
176 // This will have the effect of deleting this view.
177 delegate_->OnPreviewDismissed(this);
178}
179
Manu Corneta6cf9b4f2018-06-26 22:00:31180} // namespace ash