1 // Copyright (c) 2021 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "tests/cefclient/browser/views_overlay_controls.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "include/views/cef_box_layout.h"
11 #include "include/views/cef_window.h"
12 #include "tests/cefclient/browser/views_style.h"
13
14 namespace client {
15
16 namespace {
17
18 constexpr int kInsets = 4;
19 constexpr int kLocationBarPadding = 100;
20
21 // White with 80% opacity.
22 constexpr auto kBackgroundColor = CefColorSetARGB(255 * .80, 255, 255, 255);
23
GetLabel(ViewsOverlayControls::Command command,bool maximized)24 std::string GetLabel(ViewsOverlayControls::Command command, bool maximized) {
25 switch (command) {
26 case ViewsOverlayControls::Command::kMinimize:
27 return "-";
28 case ViewsOverlayControls::Command::kMaximize:
29 return maximized ? "O" : "o";
30 case ViewsOverlayControls::Command::kClose:
31 return "X";
32 }
33 NOTREACHED();
34 return std::string();
35 }
36
37 } // namespace
38
39 ViewsOverlayControls::ViewsOverlayControls() = default;
40
Initialize(CefRefPtr<CefWindow> window,CefRefPtr<CefMenuButton> menu_button,CefRefPtr<CefView> location_bar,bool is_chrome_toolbar)41 void ViewsOverlayControls::Initialize(CefRefPtr<CefWindow> window,
42 CefRefPtr<CefMenuButton> menu_button,
43 CefRefPtr<CefView> location_bar,
44 bool is_chrome_toolbar) {
45 DCHECK(!window_);
46 DCHECK(menu_button);
47 DCHECK(location_bar);
48
49 window_ = window;
50 window_maximized_ = window_->IsMaximized();
51
52 // Window control buttons. These controls are currently text which means that
53 // we can't use a transparent background because subpixel text rendering will
54 // break. See comments on the related DCHECK in Label::PaintText.
55 panel_ = CefPanel::CreatePanel(nullptr);
56 views_style::ApplyTo(panel_);
57
58 // Use a horizontal box layout.
59 CefBoxLayoutSettings panel_layout_settings;
60 panel_layout_settings.horizontal = true;
61 panel_->SetToBoxLayout(panel_layout_settings);
62
63 panel_->AddChildView(CreateButton(ViewsOverlayControls::Command::kMinimize));
64 panel_->AddChildView(CreateButton(ViewsOverlayControls::Command::kMaximize));
65 panel_->AddChildView(CreateButton(ViewsOverlayControls::Command::kClose));
66
67 panel_controller_ =
68 window->AddOverlayView(panel_, CEF_DOCKING_MODE_TOP_RIGHT);
69 panel_controller_->SetVisible(true);
70
71 // Menu button.
72 menu_button->SetBackgroundColor(kBackgroundColor);
73 menu_controller_ =
74 window_->AddOverlayView(menu_button, CEF_DOCKING_MODE_TOP_LEFT);
75 menu_controller_->SetInsets(CefInsets(kInsets, kInsets, 0, 0));
76 menu_controller_->SetVisible(true);
77
78 // Location bar. Will be made visible in UpdateControls().
79 location_bar_ = location_bar;
80 is_chrome_toolbar_ = is_chrome_toolbar;
81 // Use a 100% transparent background for the Chrome toolbar.
82 location_bar_->SetBackgroundColor(is_chrome_toolbar_ ? 0 : kBackgroundColor);
83 location_controller_ =
84 window_->AddOverlayView(location_bar_, CEF_DOCKING_MODE_CUSTOM);
85 }
86
Destroy()87 void ViewsOverlayControls::Destroy() {
88 window_ = nullptr;
89 panel_ = nullptr;
90 panel_controller_->Destroy();
91 panel_controller_ = nullptr;
92 menu_controller_->Destroy();
93 menu_controller_ = nullptr;
94 location_bar_ = nullptr;
95 location_controller_->Destroy();
96 location_controller_ = nullptr;
97 }
98
UpdateControls()99 void ViewsOverlayControls::UpdateControls() {
100 // Update location bar size, position and visibility.
101 auto bounds = window_->GetBounds();
102 bounds.x = kLocationBarPadding;
103 bounds.width -= kLocationBarPadding * 2;
104 bounds.y = kInsets;
105 if (is_chrome_toolbar_) {
106 // Fit the standard Chrome toolbar.
107 const auto preferred_size = location_bar_->GetPreferredSize();
108 bounds.height =
109 std::max(menu_controller_->GetSize().height, preferred_size.height);
110 } else {
111 bounds.height = menu_controller_->GetSize().height;
112 }
113 if (bounds.width < kLocationBarPadding * 2) {
114 // Not enough space.
115 location_controller_->SetVisible(false);
116 } else {
117 location_bar_->SetSize(CefSize(bounds.width, bounds.height));
118 location_controller_->SetBounds(bounds);
119 location_controller_->SetVisible(true);
120 }
121
122 MaybeUpdateMaximizeButton();
123 }
124
UpdateDraggableRegions(std::vector<CefDraggableRegion> & window_regions)125 void ViewsOverlayControls::UpdateDraggableRegions(
126 std::vector<CefDraggableRegion>& window_regions) {
127 if (panel_controller_ && panel_controller_->IsVisible()) {
128 window_regions.push_back(CefDraggableRegion(panel_controller_->GetBounds(),
129 /*draggable=*/false));
130 }
131
132 if (menu_controller_ && menu_controller_->IsVisible()) {
133 window_regions.push_back(
134 CefDraggableRegion(menu_controller_->GetBounds(), /*draggable=*/false));
135 }
136
137 if (location_controller_ && location_controller_->IsVisible()) {
138 window_regions.push_back(CefDraggableRegion(
139 location_controller_->GetBounds(), /*draggable=*/false));
140 }
141 }
142
OnButtonPressed(CefRefPtr<CefButton> button)143 void ViewsOverlayControls::OnButtonPressed(CefRefPtr<CefButton> button) {
144 auto command = static_cast<Command>(button->GetID());
145 switch (command) {
146 case ViewsOverlayControls::Command::kMinimize:
147 window_->Minimize();
148 break;
149 case ViewsOverlayControls::Command::kMaximize:
150 if (window_->IsMaximized())
151 window_->Restore();
152 else
153 window_->Maximize();
154 break;
155 case ViewsOverlayControls::Command::kClose:
156 window_->Close();
157 return;
158 }
159
160 // Explicitly reset button state because the button may have moved and it
161 // won't receive the corresponding mouse move events.
162 button->SetState(CEF_BUTTON_STATE_NORMAL);
163 button->SetInkDropEnabled(false);
164 button->SetInkDropEnabled(true);
165
166 if (command == Command::kMaximize)
167 MaybeUpdateMaximizeButton();
168 }
169
CreateButton(Command command)170 CefRefPtr<CefLabelButton> ViewsOverlayControls::CreateButton(Command command) {
171 CefRefPtr<CefLabelButton> button = CefLabelButton::CreateLabelButton(
172 this, GetLabel(command, window_maximized_));
173 button->SetID(static_cast<int>(command));
174 views_style::ApplyTo(button);
175 button->SetInkDropEnabled(true);
176 button->SetFocusable(false); // Don't give focus to the button.
177 return button;
178 }
179
MaybeUpdateMaximizeButton()180 void ViewsOverlayControls::MaybeUpdateMaximizeButton() {
181 if (window_->IsMaximized() == window_maximized_)
182 return;
183 window_maximized_ = !window_maximized_;
184
185 auto max_button = panel_->GetChildViewAt(1);
186 auto command = static_cast<Command>(max_button->GetID());
187 DCHECK(command == Command::kMaximize);
188 max_button->AsButton()->AsLabelButton()->SetText(
189 GetLabel(command, window_maximized_));
190
191 // Adjust overlay size and placement due to layout changing.
192 panel_controller_->SizeToPreferredSize();
193 }
194
195 } // namespace client
196