1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "athena/activity/activity_frame_view.h"
6
7#include "athena/activity/public/activity_view_model.h"
8#include "athena/wm/public/window_manager.h"
9#include "ui/base/hit_test.h"
10#include "ui/gfx/canvas.h"
11#include "ui/gfx/image/image_skia.h"
12#include "ui/views/background.h"
13#include "ui/views/controls/image_view.h"
14#include "ui/views/controls/label.h"
15#include "ui/views/view.h"
16#include "ui/views/widget/widget.h"
17#include "ui/views/widget/widget_delegate.h"
18#include "ui/views/window/client_view.h"
19
20namespace athena {
21namespace {
22
23// The icon size.
24const int kIconSize = 32;
25
26// The distance between the icon and the title when the icon is visible.
27const int kIconTitleSpacing = 10;
28
29// The height of the top border necessary to display the title without the icon.
30const int kDefaultTitleHeight = 25;
31
32// The height of the top border in overview mode.
33const int kOverviewTitleHeight = 55;
34
35// The height of the top border for fullscreen and frameless activities in
36// overview mode.
37const int kOverviewShortTitleHeight = 30;
38
39// The thickness of the left, right and bottom borders in overview mode.
40const int kOverviewBorderThickness = 5;
41
42}  // namespace
43
44// static
45const char ActivityFrameView::kViewClassName[] = "ActivityFrameView";
46
47ActivityFrameView::ActivityFrameView(views::Widget* frame,
48                                     ActivityViewModel* view_model)
49    : frame_(frame),
50      view_model_(view_model),
51      title_(new views::Label),
52      icon_(new views::ImageView),
53      in_overview_(false) {
54  title_->SetEnabledColor(SkColorSetA(SK_ColorBLACK, 0xe5));
55
56  AddChildView(title_);
57  AddChildView(icon_);
58
59  UpdateWindowTitle();
60  UpdateWindowIcon();
61
62  WindowManager::Get()->AddObserver(this);
63}
64
65ActivityFrameView::~ActivityFrameView() {
66  WindowManager::Get()->RemoveObserver(this);
67}
68
69gfx::Rect ActivityFrameView::GetBoundsForClientView() const {
70  gfx::Rect client_bounds = bounds();
71  client_bounds.Inset(NonClientBorderInsets());
72  return client_bounds;
73}
74
75gfx::Rect ActivityFrameView::GetWindowBoundsForClientBounds(
76    const gfx::Rect& client_bounds) const {
77  gfx::Rect window_bounds = client_bounds;
78  window_bounds.Inset(-NonClientBorderInsets());
79  return window_bounds;
80}
81
82int ActivityFrameView::NonClientHitTest(const gfx::Point& point) {
83  if (!bounds().Contains(point))
84    return HTNOWHERE;
85  int client_hit_test = frame_->client_view()->NonClientHitTest(point);
86  if (client_hit_test != HTNOWHERE)
87    return client_hit_test;
88  int window_hit_test =
89      GetHTComponentForFrame(point, 0, NonClientBorderThickness(), 0, 0, false);
90  return (window_hit_test == HTNOWHERE) ? HTCAPTION : client_hit_test;
91}
92
93void ActivityFrameView::GetWindowMask(const gfx::Size& size,
94                                      gfx::Path* window_mask) {
95}
96
97void ActivityFrameView::ResetWindowControls() {
98}
99
100void ActivityFrameView::UpdateWindowIcon() {
101  // The activity has a frame in overview mode regardless of the value of
102  // ActivityViewModel::UsesFrame().
103  SkColor bgcolor = view_model_->GetRepresentativeColor();
104  set_background(views::Background::CreateSolidBackground(bgcolor));
105  title_->SetBackgroundColor(bgcolor);
106
107  if (view_model_->UsesFrame())
108    icon_->SetImage(view_model_->GetIcon());
109  SchedulePaint();
110}
111
112void ActivityFrameView::UpdateWindowTitle() {
113  if (!view_model_->UsesFrame())
114    return;
115  title_->SetText(frame_->widget_delegate()->GetWindowTitle());
116  Layout();
117}
118
119void ActivityFrameView::SizeConstraintsChanged() {
120}
121
122gfx::Size ActivityFrameView::GetPreferredSize() const {
123  gfx::Size pref = frame_->client_view()->GetPreferredSize();
124  gfx::Rect bounds(0, 0, pref.width(), pref.height());
125  return frame_->non_client_view()
126      ->GetWindowBoundsForClientBounds(bounds)
127      .size();
128}
129
130const char* ActivityFrameView::GetClassName() const {
131  return kViewClassName;
132}
133
134void ActivityFrameView::Layout() {
135  if (frame_->IsFullscreen() || !view_model_->UsesFrame()) {
136    title_->SetVisible(false);
137    icon_->SetVisible(false);
138    return;
139  }
140
141  title_->SetVisible(true);
142  icon_->SetVisible(in_overview_);
143
144  gfx::Size preferred_title_size = title_->GetPreferredSize();
145  int top_height = NonClientTopBorderHeight();
146  int title_x = 0;
147  if (in_overview_) {
148    int edge = (top_height - kIconSize) / 2;
149    icon_->SetBounds(edge, edge, kIconSize, kIconSize);
150
151    title_x = icon_->bounds().right() + kIconTitleSpacing;
152  } else {
153    title_x = (width() - preferred_title_size.width()) / 2;
154  }
155
156  title_->SetBounds(title_x,
157                    (top_height - preferred_title_size.height()) / 2,
158                    preferred_title_size.width(),
159                    preferred_title_size.height());
160}
161
162void ActivityFrameView::OnPaintBackground(gfx::Canvas* canvas) {
163  View::OnPaintBackground(canvas);
164
165  // Paint a border around the client view.
166  gfx::Rect border_bounds = GetLocalBounds();
167  border_bounds.Inset(NonClientBorderInsets());
168  border_bounds.Inset(-1, -1, 0, 0);
169  canvas->DrawRect(border_bounds, SkColorSetA(SK_ColorGRAY, 0x7f));
170}
171
172void ActivityFrameView::OnOverviewModeEnter() {
173  view_model_->PrepareContentsForOverview();
174  in_overview_ = true;
175  InvalidateLayout();
176  frame_->client_view()->InvalidateLayout();
177  frame_->GetRootView()->Layout();
178  SchedulePaint();
179}
180
181void ActivityFrameView::OnOverviewModeExit() {
182  in_overview_ = false;
183  InvalidateLayout();
184  frame_->client_view()->InvalidateLayout();
185  frame_->GetRootView()->Layout();
186  SchedulePaint();
187  view_model_->ResetContentsView();
188}
189
190void ActivityFrameView::OnSplitViewModeEnter() {
191}
192
193void ActivityFrameView::OnSplitViewModeExit() {
194}
195
196gfx::Insets ActivityFrameView::NonClientBorderInsets() const {
197  int border_thickness = NonClientBorderThickness();
198  return gfx::Insets(NonClientTopBorderHeight(),
199                     border_thickness,
200                     border_thickness,
201                     border_thickness);
202}
203
204int ActivityFrameView::NonClientBorderThickness() const {
205  return in_overview_ ? kOverviewBorderThickness : 0;
206}
207
208int ActivityFrameView::NonClientTopBorderHeight() const {
209  if (frame_->IsFullscreen() || !view_model_->UsesFrame())
210    return in_overview_ ? kOverviewShortTitleHeight : 0;
211  return in_overview_ ? kOverviewTitleHeight : kDefaultTitleHeight;
212}
213
214}  // namespace athena
215