#include "chromeos/ui/frame/frame_view_chromeos.h"
#include <memory>
#include "chromeos/ui/base/window_properties.h"
#include "chromeos/ui/base/window_state_type.h"
#include "chromeos/ui/frame/default_frame_header.h"
#include "chromeos/ui/frame/frame_utils.h"
#include "chromeos/ui/frame/header_view.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/color/color_id.h"
#include "ui/display/screen.h"
#include "ui/display/tablet_state.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/view.h"
#include "ui/views/view_targeter.h"
#include "ui/views/widget/widget.h"
namespace chromeos {
FrameViewChromeOS::OverlayView::OverlayView(HeaderView* header_view)
: header_view_(header_view) {
SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
}
FrameViewChromeOS::OverlayView::~OverlayView() = default;
void FrameViewChromeOS::OverlayView::Layout(PassKey) {
header_view_->DeprecatedLayoutImmediately();
int onscreen_height = header_view_->GetPreferredOnScreenHeight();
int height = header_view_->GetPreferredHeight();
if (onscreen_height == 0 || !GetVisible()) {
header_view_->SetVisible(false);
header_view_->SetBounds(0, 0, width(), height);
} else {
header_view_->SetBounds(0, onscreen_height - height, width(), height);
header_view_->SetVisible(true);
}
}
bool FrameViewChromeOS::OverlayView::DoesIntersectRect(
const views::View* target,
const gfx::Rect& rect) const {
DCHECK_EQ(target, this);
return header_view_->HitTestRect(rect);
}
BEGIN_METADATA(FrameViewChromeOS, OverlayView)
END_METADATA
FrameViewChromeOS::FrameViewChromeOS(views::Widget* widget) : widget_(widget) {
DCHECK(widget_);
auto header_view = std::make_unique<HeaderView>(widget_, this);
header_view->Init();
auto overlay_view = std::make_unique<OverlayView>(header_view.get());
header_view_ = overlay_view->AddChildView(std::move(header_view));
overlay_view_ = overlay_view.get();
widget_->non_client_view()->SetOverlayView(overlay_view.release());
UpdateDefaultFrameColors();
}
FrameViewChromeOS::~FrameViewChromeOS() = default;
HeaderView* FrameViewChromeOS::GetHeaderView() {
return header_view_;
}
int FrameViewChromeOS::NonClientTopBorderHeight() const {
const aura::Window* frame_window = widget_->GetNativeWindow();
const WindowStateType window_state_type =
frame_window->GetProperty(kWindowStateTypeKey);
const bool is_in_tablet_mode = display::Screen::Get()->InTabletMode();
const bool should_have_frame_in_tablet =
window_state_type == chromeos::WindowStateType::kFloated ||
window_state_type == chromeos::WindowStateType::kNormal;
if (widget_->IsFullscreen() || !GetFrameEnabled() ||
header_view_->in_immersive_mode() ||
(is_in_tablet_mode && !should_have_frame_in_tablet)) {
return 0;
}
return header_view_->GetPreferredHeight();
}
gfx::Rect FrameViewChromeOS::GetBoundsForClientView() const {
gfx::Rect client_bounds = bounds();
client_bounds.Inset(gfx::Insets::TLBR(NonClientTopBorderHeight(), 0, 0, 0));
return client_bounds;
}
gfx::Rect FrameViewChromeOS::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
gfx::Rect window_bounds = client_bounds;
window_bounds.Inset(gfx::Insets::TLBR(-NonClientTopBorderHeight(), 0, 0, 0));
return window_bounds;
}
int FrameViewChromeOS::NonClientHitTest(const gfx::Point& point) {
return FrameBorderNonClientHitTest(this, point);
}
void FrameViewChromeOS::GetWindowMask(const gfx::Size& size,
SkPath* window_mask) {
}
void FrameViewChromeOS::ResetWindowControls() {
header_view_->ResetWindowControls();
}
void FrameViewChromeOS::UpdateWindowTitle() {
header_view_->SchedulePaintForTitle();
}
void FrameViewChromeOS::SizeConstraintsChanged() {
header_view_->UpdateCaptionButtons();
}
views::View::Views FrameViewChromeOS::GetChildrenInZOrder() {
return header_view_->GetFrameHeader()->GetAdjustedChildrenInZOrder(this);
}
gfx::Size FrameViewChromeOS::CalculatePreferredSize(
const views::SizeBounds& available_size) const {
gfx::Size pref = widget_->client_view()->GetPreferredSize(available_size);
gfx::Rect bounds(0, 0, pref.width(), pref.height());
return widget_->non_client_view()
->GetWindowBoundsForClientBounds(bounds)
.size();
}
void FrameViewChromeOS::Layout(PassKey) {
LayoutSuperclass<views::FrameView>(this);
if (!GetFrameEnabled())
return;
aura::Window* frame_window = widget_->GetNativeWindow();
frame_window->SetProperty(aura::client::kTopViewInset,
NonClientTopBorderHeight());
}
gfx::Size FrameViewChromeOS::GetMinimumSize() const {
if (!GetFrameEnabled())
return gfx::Size();
gfx::Size min_client_view_size(widget_->client_view()->GetMinimumSize());
return gfx::Size(
std::max(header_view_->GetMinimumWidth(), min_client_view_size.width()),
NonClientTopBorderHeight() + min_client_view_size.height());
}
gfx::Size FrameViewChromeOS::GetMaximumSize() const {
gfx::Size max_client_size(widget_->client_view()->GetMaximumSize());
int width = 0;
int height = 0;
if (max_client_size.width() > 0)
width = std::max(header_view_->GetMinimumWidth(), max_client_size.width());
if (max_client_size.height() > 0)
height = NonClientTopBorderHeight() + max_client_size.height();
return gfx::Size(width, height);
}
void FrameViewChromeOS::OnThemeChanged() {
FrameView::OnThemeChanged();
UpdateDefaultFrameColors();
}
void FrameViewChromeOS::UpdateDefaultFrameColors() {
aura::Window* frame_window = widget_->GetNativeWindow();
if (!frame_window->GetProperty(kTrackDefaultFrameColors))
return;
auto* color_provider = widget_->GetColorProvider();
frame_window->SetProperty(kFrameActiveColorKey,
color_provider->GetColor(ui::kColorFrameActive));
frame_window->SetProperty(kFrameInactiveColorKey,
color_provider->GetColor(ui::kColorFrameInactive));
}
bool FrameViewChromeOS::DoesIntersectRect(const views::View* target,
const gfx::Rect& rect) const {
DCHECK_EQ(target, this);
if (frame_enabled_ && overlay_view_->HitTestRect(rect))
return false;
gfx::RectF rect_in_client_view_coords_f(rect);
View::ConvertRectToTarget(this, widget_->client_view(),
&rect_in_client_view_coords_f);
gfx::Rect rect_in_client_view_coords =
gfx::ToEnclosingRect(rect_in_client_view_coords_f);
return widget_->client_view()->HitTestRect(rect_in_client_view_coords);
}
void FrameViewChromeOS::PaintAsActiveChanged() {
header_view_->GetFrameHeader()->SetPaintAsActive(ShouldPaintAsActive());
widget_->non_client_view()->DeprecatedLayoutImmediately();
}
void FrameViewChromeOS::OnDisplayTabletStateChanged(
display::TabletState state) {
switch (state) {
case display::TabletState::kEnteringTabletMode:
case display::TabletState::kExitingTabletMode:
break;
case display::TabletState::kInTabletMode:
case display::TabletState::kInClamshellMode:
InvalidateLayout();
break;
}
}
BEGIN_METADATA(FrameViewChromeOS)
END_METADATA
}