blob: 75582ce79787e65258b838df7c560907234c3d2d [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/hud_display/hud_display.h"
#include "ash/fast_ink/view_tree_host_root_view.h"
#include "ash/fast_ink/view_tree_host_widget.h"
#include "ash/hud_display/graphs_container_view.h"
#include "ash/hud_display/hud_constants.h"
#include "ash/hud_display/hud_header_view.h"
#include "ash/hud_display/hud_properties.h"
#include "ash/hud_display/hud_settings_view.h"
#include "ash/hud_display/tab_strip.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "base/strings/utf_string_conversions.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
#include "ui/events/base_event_utils.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace ash {
namespace hud_display {
namespace {
constexpr size_t kHUDGraphsInset = 5;
// Default HUDDisplayView height.
constexpr size_t kDefaultHUDGraphHeight = 300;
// Top border + Header height + margin + graph height + bottom border..
constexpr int kHUDViewDefaultHeight =
kHUDInset + (kHUDSettingsIconSize + 2 * kSettingsIconBorder) +
kHUDGraphsInset + kDefaultHUDGraphHeight + kHUDInset;
views::Widget* g_hud_widget = nullptr;
// ClientView that return HTNOWHERE by default. A child view can receive event
// by setting kHitTestComponentKey property to HTCLIENT.
class HTClientView : public views::ClientView {
public:
METADATA_HEADER(HTClientView);
HTClientView(HUDDisplayView* hud_display,
views::Widget* widget,
views::View* contents_view)
: views::ClientView(widget, contents_view), hud_display_(hud_display) {}
HTClientView(const HTClientView&) = delete;
HTClientView& operator=(const HTClientView&) = delete;
~HTClientView() override = default;
// views::ClientView
int NonClientHitTest(const gfx::Point& point) override {
return hud_display_->NonClientHitTest(point);
}
private:
HUDDisplayView* hud_display_;
};
BEGIN_METADATA(HTClientView, views::ClientView)
END_METADATA
std::unique_ptr<views::ClientView> MakeClientView(views::Widget* widget) {
auto view = std::make_unique<HUDDisplayView>();
auto* weak_view = view.get();
return std::make_unique<HTClientView>(weak_view, widget, view.release());
}
void InitializeFrameView(views::WidgetDelegate* delegate) {
auto* frame_view = delegate->GetWidget()->non_client_view()->frame_view();
// TODO(oshima): support component type with TYPE_WINDOW_FLAMELESS widget.
if (frame_view) {
frame_view->SetEnabled(false);
frame_view->SetVisible(false);
}
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// HUDDisplayView, public:
BEGIN_METADATA(HUDDisplayView, views::View)
END_METADATA
// static
void HUDDisplayView::Destroy() {
delete g_hud_widget;
g_hud_widget = nullptr;
}
// static
void HUDDisplayView::Toggle() {
if (g_hud_widget) {
Destroy();
return;
}
auto delegate = std::make_unique<views::WidgetDelegate>();
delegate->SetClientViewFactory(base::BindOnce(&MakeClientView));
delegate->RegisterWidgetInitializedCallback(
base::BindOnce(&InitializeFrameView, base::Unretained(delegate.get())));
delegate->SetOwnedByWidget(true);
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.delegate = delegate.release();
params.parent = Shell::GetContainer(Shell::GetPrimaryRootWindow(),
kShellWindowId_OverlayContainer);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
// Adjust for 1px grid width around the graph.
params.bounds =
gfx::Rect(kDefaultGraphWidth + 2 * kHUDInset + 2 * kGridLineWidth,
kHUDViewDefaultHeight + 2 * kGridLineWidth);
auto* widget = CreateViewTreeHostWidget(std::move(params));
widget->GetLayer()->SetName("HUDDisplayView");
widget->Show();
g_hud_widget = widget;
}
HUDDisplayView::HUDDisplayView() {
DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
// Layout:
// ----------------------
// | Header | // Buttons, tabs, controls
// ----------------------
// | | // Data views full-size, z-stacked.
// | Data |
// | |
// ----------------------
// Create two child views for header and data. Vertically stacked.
views::BoxLayout* layout_manager =
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
layout_manager->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStretch);
header_view_ = AddChildView(std::make_unique<HUDHeaderView>(this));
views::View* data = AddChildView(std::make_unique<views::View>());
// Data view takes the rest of the host view.
layout_manager->SetFlexForView(data, 1, /*use_min_size=*/false);
// Setup header.
header_view_->tab_strip()->AddTabButton(DisplayMode::CPU_DISPLAY,
base::ASCIIToUTF16("CPU"));
header_view_->tab_strip()->AddTabButton(DisplayMode::MEMORY_DISPLAY,
base::ASCIIToUTF16("RAM"));
header_view_->tab_strip()->AddTabButton(DisplayMode::FPS_DISPLAY,
base::ASCIIToUTF16("FPS"));
// Setup data.
data->SetBackground(views::CreateSolidBackground(kHUDBackground));
data->SetBorder(views::CreateEmptyBorder(
gfx::Insets(kHUDGraphsInset, kHUDInset, kHUDInset, kHUDInset)));
// We have two child views z-stacked.
// The bottom one is GraphsContainerView with all the graph lines.
// The top one is settings UI overlay.
data->SetLayoutManager(std::make_unique<views::FillLayout>());
graphs_container_ =
data->AddChildView(std::make_unique<GraphsContainerView>());
settings_view_ = data->AddChildView(std::make_unique<HUDSettingsView>());
settings_view_->SetVisible(false);
// CPU display is active by default.
SetDisplayMode(DisplayMode::CPU_DISPLAY);
}
HUDDisplayView::~HUDDisplayView() {
DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
}
// There is only one button.
void HUDDisplayView::OnSettingsToggle() {
settings_view_->ToggleVisibility();
graphs_container_->SetVisible(!settings_view_->GetVisible());
}
int HUDDisplayView::NonClientHitTest(const gfx::Point& point) {
const View* view = GetEventHandlerForPoint(point);
if (!view)
return HTNOWHERE;
return view->GetProperty(kHUDClickHandler);
}
void HUDDisplayView::SetDisplayMode(DisplayMode display_mode) {
graphs_container_->SetMode(display_mode);
header_view_->tab_strip()->ActivateTab(display_mode);
}
} // namespace hud_display
} // namespace ash