blob: d75a884fda16b3ff31804246ace8a9660cca5223 [file] [log] [blame]
// Copyright 2019 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/wm/desks/desk_mini_view.h"
#include <algorithm>
#include "ash/wm/desks/close_desk_button.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desks_controller.h"
#include "ui/aura/window.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
constexpr int kDeskPreviewHeight = 64;
constexpr int kLabelPreviewSpacing = 8;
constexpr int kCloseButtonMargin = 2;
constexpr gfx::Size kCloseButtonSize{24, 24};
// The desk preview bounds are proportional to the bounds of the display on
// which it resides, but always has a fixed height `kDeskPreviewHeight`.
gfx::Rect GetDeskPreviewBounds(aura::Window* root_window) {
const auto root_size = root_window->GetBoundsInRootWindow().size();
return gfx::Rect(kDeskPreviewHeight * root_size.width() / root_size.height(),
kDeskPreviewHeight);
}
} // namespace
// -----------------------------------------------------------------------------
// A view that shows the contents of the corresponding desk in its mini_view.
class DeskPreviewView : public views::View {
public:
explicit DeskPreviewView(DeskMiniView* mini_view) : mini_view_(mini_view) {
// For now use a solid color layer.
SetPaintToLayer(ui::LAYER_SOLID_COLOR);
layer()->SetColor(SK_ColorDKGRAY);
// TODO(afakhry):
// - Ability to mark this preview as active.
// - Actually mirror the contents of the corresponding desk.
}
~DeskPreviewView() override = default;
// ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override {
switch (event->type()) {
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_RELEASED:
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
mini_view_->OnHoverStateMayHaveChanged();
break;
default:
break;
}
}
private:
DeskMiniView* mini_view_;
DISALLOW_COPY_AND_ASSIGN(DeskPreviewView);
};
// -----------------------------------------------------------------------------
// DeskMiniView
DeskMiniView::DeskMiniView(const Desk* desk,
const base::string16& title,
views::ButtonListener* listener)
: views::Button(listener),
desk_(desk),
desk_preview_(new DeskPreviewView(this)),
label_(new views::Label(title)),
close_desk_button_(new CloseDeskButton(this)) {
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
label_->SetAutoColorReadabilityEnabled(false);
label_->SetSubpixelRenderingEnabled(false);
label_->set_can_process_events_within_subtree(false);
label_->SetEnabledColor(SK_ColorWHITE);
label_->SetLineHeight(10);
close_desk_button_->SetVisible(false);
// TODO(afakhry): Tooltips and accessible names.
AddChildView(desk_preview_);
AddChildView(label_);
AddChildView(close_desk_button_);
SetFocusPainter(nullptr);
SetInkDropMode(InkDropMode::OFF);
SchedulePaint();
}
DeskMiniView::~DeskMiniView() = default;
void DeskMiniView::SetTitle(const base::string16& title) {
label_->SetText(title);
}
void DeskMiniView::OnHoverStateMayHaveChanged() {
// TODO(afakhry): In tablet mode, discuss showing the close button on long
// press.
close_desk_button_->SetVisible(DesksController::Get()->CanRemoveDesks() &&
IsMouseHovered());
}
const char* DeskMiniView::GetClassName() const {
return "DeskMiniView";
}
void DeskMiniView::Layout() {
auto* root_window = GetWidget()->GetNativeWindow()->GetRootWindow();
DCHECK(root_window);
const gfx::Rect preview_bounds = GetDeskPreviewBounds(root_window);
desk_preview_->SetBoundsRect(preview_bounds);
const gfx::Size label_size = label_->GetPreferredSize();
const gfx::Rect label_bounds{
(preview_bounds.width() - label_size.width()) / 2,
preview_bounds.bottom() + kLabelPreviewSpacing, label_size.width(),
label_size.height()};
label_->SetBoundsRect(label_bounds);
close_desk_button_->SetBounds(
preview_bounds.right() - kCloseButtonSize.width() - kCloseButtonMargin,
kCloseButtonMargin, kCloseButtonSize.width(), kCloseButtonSize.height());
Button::Layout();
SchedulePaint();
}
gfx::Size DeskMiniView::CalculatePreferredSize() const {
auto* root_window = GetWidget()->GetNativeWindow()->GetRootWindow();
DCHECK(root_window);
const gfx::Size label_size = label_->GetPreferredSize();
const gfx::Rect preview_bounds = GetDeskPreviewBounds(root_window);
return gfx::Size{
std::max(preview_bounds.width(), label_size.width()),
preview_bounds.height() + kLabelPreviewSpacing + label_size.height()};
}
void DeskMiniView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender != close_desk_button_)
return;
// This mini_view can no longer be pressed.
listener_ = nullptr;
auto* controller = DesksController::Get();
DCHECK(controller->CanRemoveDesks());
controller->RemoveDesk(desk_);
}
void DeskMiniView::OnMouseEvent(ui::MouseEvent* event) {
switch (event->type()) {
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_RELEASED:
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
OnHoverStateMayHaveChanged();
break;
default:
break;
}
}
} // namespace ash