Commit 6b3b9345 authored by Alexander Alekseev's avatar Alexander Alekseev Committed by Commit Bot

Add settings UI to Ash HUD Display.

This adds settings page to Ash HUD and makes HUT semi-transparent.

Just the HUD:
https://screenshot.googleplex.com/ZBqYnQDomH5.png

With the settings button:
https://screenshot.googleplex.com/pNCfTAw9J92.png

With settings UI displayed:
https://screenshot.googleplex.com/SwyNb0xVDbc.png

Bug: 1075612

Change-Id: I9f26e8b99f03e0d638f854312820f10ec25ee6a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2223974
Commit-Queue: Alexander Alekseev <alemate@chromium.org>
Reviewed-by: default avatarMitsuru Oshima (slow:gardening) <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#780199}
parent d05b87c9
......@@ -422,8 +422,13 @@ component("ash") {
"hud_display/graph.h",
"hud_display/graphs_container_view.cc",
"hud_display/graphs_container_view.h",
"hud_display/hud_constants.h",
"hud_display/hud_display.cc",
"hud_display/hud_display.h",
"hud_display/hud_properties.cc",
"hud_display/hud_properties.h",
"hud_display/hud_settings_view.cc",
"hud_display/hud_settings_view.h",
"hud_display/memory_status.cc",
"hud_display/memory_status.h",
"ime/ime_controller_impl.cc",
......
......@@ -9,6 +9,7 @@
#include <sstream>
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/gfx/canvas.h"
......@@ -106,6 +107,7 @@ void Graph::Draw(gfx::Canvas* canvas) const {
}
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setBlendMode(SkBlendMode::kSrc);
const cc::PaintFlags::Style style = (fill_ == Graph::Fill::NONE)
? cc::PaintFlags::kStroke_Style
: cc::PaintFlags::kFill_Style;
......
......@@ -6,6 +6,7 @@
#include <numeric>
#include "ash/hud_display/hud_constants.h"
#include "base/bind.h"
#include "base/task/post_task.h"
#include "ui/gfx/canvas.h"
......@@ -23,31 +24,35 @@ constexpr base::TimeDelta kGraphsDataRefreshInterval =
////////////////////////////////////////////////////////////////////////////////
// GraphsContainerView, public:
BEGIN_METADATA(GraphsContainerView)
METADATA_PARENT_CLASS(View)
END_METADATA()
GraphsContainerView::GraphsContainerView()
: graph_chrome_rss_private_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
SK_ColorRED),
SkColorSetA(SK_ColorRED, kHUDAlpha)),
graph_mem_free_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::NONE,
SK_ColorDKGRAY),
SkColorSetA(SK_ColorDKGRAY, kHUDAlpha)),
graph_mem_used_unknown_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
SK_ColorLTGRAY),
SkColorSetA(SK_ColorLTGRAY, kHUDAlpha)),
graph_renderers_rss_private_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
SK_ColorCYAN),
SkColorSetA(SK_ColorCYAN, kHUDAlpha)),
graph_arc_rss_private_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
SK_ColorMAGENTA),
SkColorSetA(SK_ColorMAGENTA, kHUDAlpha)),
graph_gpu_rss_private_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
SK_ColorRED),
SkColorSetA(SK_ColorRED, kHUDAlpha)),
graph_gpu_kernel_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
SK_ColorYELLOW),
SkColorSetA(SK_ColorYELLOW, kHUDAlpha)),
graph_chrome_rss_shared_(Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::NONE,
SK_ColorBLUE) {
SkColorSetA(SK_ColorBLUE, kHUDAlpha)) {
DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
refresh_timer_.Start(FROM_HERE, kGraphsDataRefreshInterval, this,
......
......@@ -17,6 +17,8 @@ namespace hud_display {
// GraphsContainerView class draws a bunch of graphs.
class GraphsContainerView : public views::View {
public:
METADATA_HEADER(GraphsContainerView);
GraphsContainerView();
~GraphsContainerView() override;
......
// 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.
#ifndef ASH_HUD_DISPLAY_HUD_CONSTANTS_H_
#define ASH_HUD_DISPLAY_HUD_CONSTANTS_H_
#include "third_party/skia/include/core/SkColor.h"
namespace ash {
namespace hud_display {
constexpr SkAlpha kHUDAlpha = 204; // = 0.8 * 255
} // namespace hud_display
} // namespace ash
#endif // ASH_HUD_DISPLAY_HUD_CONSTANTS_H_
......@@ -7,14 +7,23 @@
#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_properties.h"
#include "ash/hud_display/hud_settings_view.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/root_window_controller.h"
#include "ash/shell.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/gfx/canvas.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
......@@ -22,15 +31,110 @@ namespace ash {
namespace hud_display {
namespace {
constexpr int kVectorIconSize = 18;
std::unique_ptr<views::Widget> g_hud_widget;
constexpr SkColor kBackground = SkColorSetARGB(208, 17, 17, 17);
constexpr SkColor kBackground = SkColorSetARGB(kHUDAlpha, 17, 17, 17);
// Basically views::SolidBackground with SkBlendMode::kSrc paint mode.
class SolidSourceBackground : public views::Background {
public:
explicit SolidSourceBackground(SkColor color) {
SetNativeControlColor(color);
}
SolidSourceBackground(const SolidSourceBackground&) = delete;
SolidSourceBackground& operator=(const SolidSourceBackground&) = delete;
void Paint(gfx::Canvas* canvas, views::View* /*view*/) const override {
// Fill the background. Note that we don't constrain to the bounds as
// canvas is already clipped for us.
canvas->DrawColor(get_color(), SkBlendMode::kSrc);
}
};
std::unique_ptr<views::View> CreateButtonsContainer() {
auto container = std::make_unique<views::View>();
auto layout_manager = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal);
layout_manager->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStart);
container->SetLayoutManager(std::move(layout_manager));
return container;
}
std::unique_ptr<views::ImageButton> CreateSettingsButton(HUDDisplayView* hud) {
auto button = std::make_unique<views::ImageButton>(hud);
button->SetVisible(false);
button->SetImage(
views::Button::ButtonState::STATE_NORMAL,
gfx::CreateVectorIcon(vector_icons::kSettingsIcon, kVectorIconSize,
HUDSettingsView::kDefaultColor));
button->SetBorder(views::CreateEmptyBorder(gfx::Insets(5)));
button->SetProperty(kHUDClickHandler, HTCLIENT);
button->SetBackground(std::make_unique<SolidSourceBackground>(kBackground));
return button;
}
class HUDOverlayContainerView : public views::View {
public:
METADATA_HEADER(HUDOverlayContainerView);
explicit HUDOverlayContainerView(HUDDisplayView* hud);
~HUDOverlayContainerView() override = default;
HUDOverlayContainerView(const HUDOverlayContainerView&) = delete;
HUDOverlayContainerView& operator=(const HUDOverlayContainerView&) = delete;
HUDSettingsView* settings_view() const { return settings_view_; }
views::ImageButton* settings_trigger_button() const {
return settings_trigger_button_;
}
private:
HUDSettingsView* settings_view_ = nullptr;
views::ImageButton* settings_trigger_button_ = nullptr;
};
BEGIN_METADATA(HUDOverlayContainerView)
METADATA_PARENT_CLASS(View)
END_METADATA()
HUDOverlayContainerView::HUDOverlayContainerView(HUDDisplayView* hud) {
// Overlay container has two child views stacked vertically and stretched
// horizontally.
// The top is a container for "Settings" button.
// The bottom is Settings UI view.
views::BoxLayout* layout_manager =
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
layout_manager->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStretch);
{
// Buttons container arranges buttons horizontally and does not alter
// button sizes.
views::View* buttons_container = AddChildView(CreateButtonsContainer());
settings_trigger_button_ =
buttons_container->AddChildView(CreateSettingsButton(hud));
}
// HUDSettingsView starts invisible.
settings_view_ = AddChildView(std::make_unique<HUDSettingsView>());
// Make settings view occupy all the remaining space.
layout_manager->SetFlexForView(settings_view_, 1,
/*use_min_size=*/false);
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// HUDDisplayView, public:
BEGIN_METADATA(HUDDisplayView)
METADATA_PARENT_CLASS(WidgetDelegateView)
END_METADATA()
// static
void HUDDisplayView::Destroy() {
g_hud_widget.reset();
......@@ -50,6 +154,7 @@ void HUDDisplayView::Toggle() {
params.bounds =
gfx::Rect(Graph::kDefaultWidth + 2 * kHUDInset, kDefaultHUDHeight);
auto* widget = CreateViewTreeHostWidget(std::move(params));
widget->GetLayer()->SetName("HUDDisplayView");
widget->Show();
g_hud_widget = base::WrapUnique(widget);
......@@ -63,7 +168,18 @@ HUDDisplayView::HUDDisplayView() {
SetLayoutManager(std::make_unique<views::FillLayout>());
AddChildView(std::make_unique<GraphsContainerView>());
// We have two child views z-stacked.
// The bottom one is GraphsContainerView with all the graph lines.
// The top one lays out buttons and settings UI overlays.
graphs_container_ = AddChildView(std::make_unique<GraphsContainerView>());
HUDOverlayContainerView* overlay_container =
AddChildView(std::make_unique<HUDOverlayContainerView>(this));
settings_view_ = overlay_container->settings_view();
settings_trigger_button_ = overlay_container->settings_trigger_button();
// Receive OnMouseEnter/OnMouseLEave when hovering over the child views too.
set_notify_enter_exit_on_child(true);
}
HUDDisplayView::~HUDDisplayView() {
......@@ -72,19 +188,48 @@ HUDDisplayView::~HUDDisplayView() {
////////////////////////////////////////////////////////////////////////////////
void HUDDisplayView::OnMouseEntered(const ui::MouseEvent& /*event*/) {
settings_trigger_button_->SetVisible(true);
}
void HUDDisplayView::OnMouseExited(const ui::MouseEvent& /*event*/) {
// Button is always visible if Settings UI is visible.
if (settings_view_->GetVisible())
return;
settings_trigger_button_->SetVisible(false);
}
int HUDDisplayView::NonClientHitTest(const gfx::Point& point) {
const View* view = GetEventHandlerForPoint(point);
if (!view)
return HTNOWHERE;
return view->GetProperty(kHUDClickHandler);
}
// ClientView that return HTNOWHERE by default. A child view can receive event
// by setting kHitTestComponentKey property to HTCLIENT.
class HTClientView : public views::ClientView {
public:
HTClientView(views::Widget* widget, views::View* contents_view)
: views::ClientView(widget, contents_view) {}
HTClientView(HUDDisplayView* hud_display,
views::Widget* widget,
views::View* contents_view)
: views::ClientView(widget, contents_view), hud_display_(hud_display) {}
~HTClientView() override = default;
int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
int NonClientHitTest(const gfx::Point& point) override;
private:
HUDDisplayView* hud_display_ = nullptr;
};
int HTClientView::NonClientHitTest(const gfx::Point& point) {
return hud_display_->NonClientHitTest(point);
}
views::ClientView* HUDDisplayView::CreateClientView(views::Widget* widget) {
return new HTClientView(widget, GetContentsView());
return new HTClientView(this, widget, GetContentsView());
}
void HUDDisplayView::OnWidgetInitialized() {
......@@ -96,5 +241,12 @@ void HUDDisplayView::OnWidgetInitialized() {
}
}
// There is only one button.
void HUDDisplayView::ButtonPressed(views::Button* /*sender*/,
const ui::Event& /*event*/) {
settings_view_->ToggleVisibility();
graphs_container_->SetVisible(!settings_view_->GetVisible());
}
} // namespace hud_display
} // namespace ash
......@@ -6,14 +6,25 @@
#define ASH_HUD_DISPLAY_HUD_DISPLAY_H_
#include "base/sequence_checker.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/widget/widget_delegate.h"
namespace views {
class ImageButton;
}
namespace ash {
namespace hud_display {
class GraphsContainerView;
class HUDSettingsView;
// HUDDisplayView class can be used to display a system monitoring overview.
class HUDDisplayView : public views::WidgetDelegateView {
class HUDDisplayView : public views::WidgetDelegateView,
public views::ButtonListener {
public:
METADATA_HEADER(HUDDisplayView);
// Default HUDDisplayView height.
static constexpr size_t kDefaultHUDHeight = 300;
......@@ -26,17 +37,32 @@ class HUDDisplayView : public views::WidgetDelegateView {
HUDDisplayView(const HUDDisplayView&) = delete;
HUDDisplayView& operator=(const HUDDisplayView&) = delete;
// view::
void OnMouseEntered(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
// WidgetDelegate:
views::ClientView* CreateClientView(views::Widget* widget) override;
void OnWidgetInitialized() override;
// views::ButtonListener
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// Destroys global instance.
static void Destroy();
// Creates/Destroys global singleton.
static void Toggle();
// Called from ClientView. Responsible for moving widget when clicked outside
// of the children.
int NonClientHitTest(const gfx::Point& point);
private:
GraphsContainerView* graphs_container_ = nullptr; // not owned
HUDSettingsView* settings_view_ = nullptr; // not owned
views::ImageButton* settings_trigger_button_ = nullptr; // not owned
SEQUENCE_CHECKER(ui_sequence_checker_);
};
......
// 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_properties.h"
namespace ash {
namespace hud_display {
DEFINE_UI_CLASS_PROPERTY_KEY(HitTestCompat, kHUDClickHandler, HTNOWHERE)
} // namespace hud_display
} // namespace ash
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_EXPORT, HitTestCompat)
// 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.
#ifndef ASH_HUD_DISPLAY_HUD_PROPERTIES_H_
#define ASH_HUD_DISPLAY_HUD_PROPERTIES_H_
#include "ash/ash_export.h"
#include "ui/base/class_property.h"
#include "ui/base/hit_test.h"
namespace ash {
namespace hud_display {
// Marks view as Click event handler to make clicks on the other area drag the
// whole HUD.
extern const ui::ClassProperty<HitTestCompat>* const kHUDClickHandler;
} // namespace hud_display
} // namespace ash
DECLARE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_EXPORT, HitTestCompat)
#endif // ASH_HUD_DISPLAY_HUD_PROPERTIES_H_
// 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_settings_view.h"
#include "ash/hud_display/hud_properties.h"
#include "base/compiler_specific.h"
#include "base/strings/string16.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
namespace ash {
namespace hud_display {
BEGIN_METADATA(HUDSettingsView)
METADATA_PARENT_CLASS(View)
END_METADATA()
constexpr SkColor HUDSettingsView::kDefaultColor;
HUDSettingsView::HUDSettingsView() {
SetVisible(false);
auto layout_manager = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical);
layout_manager->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStart);
SetLayoutManager(std::move(layout_manager));
SetBorder(views::CreateSolidBorder(1, kDefaultColor));
// Use this to add checkboxes like:
// add_checkbox(this, base::ASCIIToUTF16("test1"));
auto add_checkbox = [](HUDSettingsView* self,
const base::string16& text) -> const views::Checkbox* {
auto checkbox = std::make_unique<views::Checkbox>(text, self);
const views::Checkbox* result = checkbox.get();
checkbox->SetEnabledTextColors(kDefaultColor);
checkbox->SetProperty(kHUDClickHandler, HTCLIENT);
self->AddChildView(std::move(checkbox));
return result;
};
// No checkboxes for now.
ALLOW_UNUSED_LOCAL(add_checkbox);
}
HUDSettingsView::~HUDSettingsView() = default;
void HUDSettingsView::ButtonPressed(views::Button* sender,
const ui::Event& /*event*/) {
const views::Checkbox* checkbox = static_cast<views::Checkbox*>(sender);
DVLOG(1) << "HUDSettingsView::ButtonPressed(): "
<< (checkbox->GetChecked() ? "Checked" : "Uncheked");
}
void HUDSettingsView::ToggleVisibility() {
SetVisible(!GetVisible());
}
} // namespace hud_display
} // namespace ash
// 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.
#ifndef ASH_HUD_DISPLAY_HUD_SETTINGS_VIEW_H_
#define ASH_HUD_DISPLAY_HUD_SETTINGS_VIEW_H_
#include "ash/hud_display/hud_constants.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/view.h"
namespace ash {
namespace hud_display {
class HUDSettingsView : public views::ButtonListener, public views::View {
public:
METADATA_HEADER(HUDSettingsView);
// Use light orange color.
static constexpr SkColor kDefaultColor =
SkColorSetARGB(kHUDAlpha, 0xFF, 0xB2, 0x66);
HUDSettingsView();
~HUDSettingsView() override;
HUDSettingsView(const HUDSettingsView&) = delete;
HUDSettingsView& operator=(const HUDSettingsView&) = delete;
// views::ButtonListener
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// Shows/hides the view.
void ToggleVisibility();
};
} // namespace hud_display
} // namespace ash
#endif // ASH_HUD_DISPLAY_HUD_SETTINGS_VIEW_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment