Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: ash/wm/workspace/frame_caption_button_container_view.cc

Issue 23498031: Move code related to the window controls to ash/wm/caption_buttons (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 "ash/wm/workspace/frame_caption_button_container_view.h"
6
7 #include "ash/ash_switches.h"
8 #include "ash/shell.h"
9 #include "ash/shell_delegate.h"
10 #include "ash/wm/window_settings.h"
11 #include "ash/wm/workspace/alternate_frame_caption_button.h"
12 #include "ash/wm/workspace/frame_maximize_button.h"
13 #include "grit/ash_resources.h"
14 #include "grit/ui_strings.h" // Accessibility names
15 #include "ui/base/hit_test.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
19 #include "ui/gfx/canvas.h"
20 #include "ui/views/border.h"
21 #include "ui/views/controls/button/image_button.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/widget/widget_delegate.h"
24 #include "ui/views/window/non_client_view.h"
25
26 namespace ash {
27
28 namespace {
29
30 // Constants for normal button style -------------------------------------------
31
32 // The distance between buttons. AlternateFrameCaptionButton::GetXOverlap() is
33 // used to compute the distance between buttons for the alternate button style.
34 const int kDistanceBetweenButtons = -1;
35
36 // Constants for alternate button style ----------------------------------------
37
38 // Spacings between the buttons and the view's top and bottom borders (if any).
39 const int kAlternateStyleShortHeaderTopInset = 0;
40 const int kAlternateStyleTallHeaderTopInset = 2;
41 const int kAlternateStyleShortHeaderBottomInset = 0;
42 const int kAlternateStyleTallHeaderBottomInset = 1;
43
44 // Ideal spacing between:
45 // - Right edge of the leftmost button's overlappable region and the view's left
46 // edge.
47 // - Left edge of the rightmost button's overlappable region and the view's
48 // right edge.
49 // Used in GetLeftInset() and GetRightInset().
50 const int kAlternateStyleSideInset = 5;
51
52 // Converts |point| from |src| to |dst| and hittests against |dst|.
53 bool ConvertPointToViewAndHitTest(const views::View* src,
54 const views::View* dst,
55 const gfx::Point& point) {
56 gfx::Point converted(point);
57 views::View::ConvertPointToTarget(src, dst, &converted);
58 return dst->HitTestPoint(converted);
59 }
60
61 } // namespace
62
63 // static
64 const char FrameCaptionButtonContainerView::kViewClassName[] =
65 "FrameCaptionButtonContainerView";
66
67 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView(
68 views::NonClientFrameView* frame_view,
69 views::Widget* frame,
70 MinimizeAllowed minimize_allowed)
71 : frame_(frame),
72 header_style_(HEADER_STYLE_SHORT),
73 minimize_button_(NULL),
74 size_button_(NULL),
75 close_button_(NULL) {
76 bool alternate_style = switches::UseAlternateFrameCaptionButtonStyle();
77
78 // Insert the buttons left to right.
79 if (alternate_style) {
80 minimize_button_ = new AlternateFrameCaptionButton(this,
81 AlternateFrameCaptionButton::ACTION_MINIMIZE);
82 size_button_ = new AlternateFrameCaptionButton(this,
83 AlternateFrameCaptionButton::ACTION_MAXIMIZE_RESTORE);
84 close_button_ = new AlternateFrameCaptionButton(this,
85 AlternateFrameCaptionButton::ACTION_CLOSE);
86 } else {
87 minimize_button_ = new views::ImageButton(this);
88 size_button_ = new FrameMaximizeButton(this, frame_view);
89 close_button_ = new views::ImageButton(this);
90 }
91
92 minimize_button_->SetAccessibleName(
93 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE));
94 // Hide |minimize_button_| when using the non-alternate button style because
95 // |size_button_| is capable of minimizing in this case.
96 // TODO(pkotwicz): We should probably show the minimize button when in
97 // "always maximized" mode.
98 minimize_button_->SetVisible(
99 minimize_allowed == MINIMIZE_ALLOWED &&
100 (alternate_style || !frame_->widget_delegate()->CanMaximize()));
101 AddChildView(minimize_button_);
102
103 size_button_->SetAccessibleName(
104 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE));
105 size_button_->SetVisible(frame_->widget_delegate()->CanMaximize() &&
106 !ash::Shell::IsForcedMaximizeMode());
107 AddChildView(size_button_);
108
109 close_button_->SetAccessibleName(
110 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
111 AddChildView(close_button_);
112
113 button_separator_ = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
114 IDR_AURA_WINDOW_BUTTON_SEPARATOR).AsImageSkia();
115 }
116
117 FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() {
118 }
119
120 void FrameCaptionButtonContainerView::ResetWindowControls() {
121 minimize_button_->SetState(views::CustomButton::STATE_NORMAL);
122 size_button_->SetState(views::CustomButton::STATE_NORMAL);
123 }
124
125 int FrameCaptionButtonContainerView::NonClientHitTest(
126 const gfx::Point& point) const {
127 if (close_button_->visible() &&
128 ConvertPointToViewAndHitTest(this, close_button_, point)) {
129 return HTCLOSE;
130 } else if (size_button_->visible() &&
131 ConvertPointToViewAndHitTest(this, size_button_, point)) {
132 return HTMAXBUTTON;
133 } else if (minimize_button_->visible() &&
134 ConvertPointToViewAndHitTest(this, minimize_button_, point)) {
135 return HTMINBUTTON;
136 }
137 return HTNOWHERE;
138 }
139
140 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() {
141 int button_separation = GetDistanceBetweenButtons();
142
143 int width = 0;
144 bool first_visible = true;
145 for (int i = 0; i < child_count(); ++i) {
146 views::View* child = child_at(i);
147 if (!child->visible())
148 continue;
149
150 width += child_at(i)->GetPreferredSize().width();
151 if (!first_visible)
152 width += button_separation;
153 first_visible = false;
154 }
155 gfx::Insets insets(GetInsets());
156 return gfx::Size(
157 width + insets.width() + GetLeftInset() + GetRightInset(),
158 close_button_->GetPreferredSize().height() + insets.height());
159 }
160
161 void FrameCaptionButtonContainerView::Layout() {
162 if (switches::UseAlternateFrameCaptionButtonStyle()) {
163 int top_inset = kAlternateStyleShortHeaderTopInset;
164 int bottom_inset = kAlternateStyleShortHeaderBottomInset;
165 if (header_style_ == HEADER_STYLE_TALL) {
166 top_inset = kAlternateStyleTallHeaderTopInset;
167 bottom_inset = kAlternateStyleTallHeaderBottomInset;
168 }
169
170 minimize_button_->set_border(
171 views::Border::CreateEmptyBorder(top_inset, 0, bottom_inset, 0));
172 size_button_->set_border(
173 views::Border::CreateEmptyBorder(top_inset, 0, bottom_inset, 0));
174 close_button_->set_border(
175 views::Border::CreateEmptyBorder(top_inset, 0, bottom_inset, 0));
176 } else {
177 SetButtonImages(minimize_button_,
178 IDR_AURA_WINDOW_MINIMIZE_SHORT,
179 IDR_AURA_WINDOW_MINIMIZE_SHORT_H,
180 IDR_AURA_WINDOW_MINIMIZE_SHORT_P);
181
182 if (header_style_ == HEADER_STYLE_MAXIMIZED_HOSTED_APP) {
183 SetButtonImages(size_button_,
184 IDR_AURA_WINDOW_FULLSCREEN_RESTORE,
185 IDR_AURA_WINDOW_FULLSCREEN_RESTORE_H,
186 IDR_AURA_WINDOW_FULLSCREEN_RESTORE_P);
187 SetButtonImages(close_button_,
188 IDR_AURA_WINDOW_FULLSCREEN_CLOSE,
189 IDR_AURA_WINDOW_FULLSCREEN_CLOSE_H,
190 IDR_AURA_WINDOW_FULLSCREEN_CLOSE_P);
191 } else if (header_style_ == HEADER_STYLE_SHORT) {
192 // The new assets only make sense if the window is maximized or fullscreen
193 // because we usually use a black header in this case.
194 if ((frame_->IsMaximized() || frame_->IsFullscreen()) &&
195 wm::GetWindowSettings(
196 frame_->GetNativeWindow())->tracked_by_workspace()) {
197 SetButtonImages(size_button_,
198 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2,
199 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H,
200 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P);
201 SetButtonImages(close_button_,
202 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2,
203 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H,
204 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P);
205 } else {
206 SetButtonImages(size_button_,
207 IDR_AURA_WINDOW_MAXIMIZED_RESTORE,
208 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H,
209 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P);
210 SetButtonImages(close_button_,
211 IDR_AURA_WINDOW_MAXIMIZED_CLOSE,
212 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H,
213 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P);
214 }
215 } else {
216 SetButtonImages(size_button_,
217 IDR_AURA_WINDOW_MAXIMIZE,
218 IDR_AURA_WINDOW_MAXIMIZE_H,
219 IDR_AURA_WINDOW_MAXIMIZE_P);
220 SetButtonImages(close_button_,
221 IDR_AURA_WINDOW_CLOSE,
222 IDR_AURA_WINDOW_CLOSE_H,
223 IDR_AURA_WINDOW_CLOSE_P);
224 }
225 }
226
227 gfx::Insets insets(GetInsets());
228 int x = insets.left() + GetLeftInset();
229 int y_inset = insets.top();
230 int button_separation = GetDistanceBetweenButtons();
231 for (int i = 0; i < child_count(); ++i) {
232 views::View* child = child_at(i);
233 if (!child->visible())
234 continue;
235
236 gfx::Size size = child->GetPreferredSize();
237 child->SetBounds(x, y_inset, size.width(), size.height());
238
239 // Do not allow |child| to paint over the left border.
240 child->set_clip_insets(
241 gfx::Insets(0, std::max(0, insets.left() - x), 0, 0));
242
243 x += size.width() + button_separation;
244 }
245 }
246
247 const char* FrameCaptionButtonContainerView::GetClassName() const {
248 return kViewClassName;
249 }
250
251 void FrameCaptionButtonContainerView::OnPaint(gfx::Canvas* canvas) {
252 views::View::OnPaint(canvas);
253
254 // The alternate button style and AppNonClientFrameViewAsh do not paint the
255 // button separator.
256 if (header_style_ != HEADER_STYLE_MAXIMIZED_HOSTED_APP &&
257 !switches::UseAlternateFrameCaptionButtonStyle()) {
258 // We should have at most two visible buttons. The button separator is
259 // always painted underneath the close button regardless of whether a
260 // button other than the close button is visible.
261 gfx::Rect divider(close_button_->bounds().origin(),
262 button_separator_.size());
263 canvas->DrawImageInt(button_separator_,
264 GetMirroredXForRect(divider),
265 divider.y());
266 }
267 }
268
269 int FrameCaptionButtonContainerView::GetDistanceBetweenButtons() const {
270 if (switches::UseAlternateFrameCaptionButtonStyle())
271 return AlternateFrameCaptionButton::GetXOverlap() * -2;
272 return kDistanceBetweenButtons;
273 }
274
275 int FrameCaptionButtonContainerView::GetLeftInset() const {
276 if (switches::UseAlternateFrameCaptionButtonStyle()) {
277 // If using the alternate button style and there is a border, clip the
278 // left overlappable region of the leftmost button to
279 // |kAlternateStyleSideInset|.
280 // Otherwise, allow enough room for the entire left overlappable region of
281 // the leftmost button to fit in the view.
282 if (border() && border()->GetInsets().left()) {
283 return kAlternateStyleSideInset -
284 AlternateFrameCaptionButton::GetXOverlap();
285 }
286 }
287 return 0;
288 }
289
290 int FrameCaptionButtonContainerView::GetRightInset() const {
291 if (switches::UseAlternateFrameCaptionButtonStyle()) {
292 // Always clip the right overlappable region of the rightmost button to
293 // |kAlternateStyleSideInset| because the caption buttons are always
294 // at the right edge of the screen. (The left edge in RTL mode).
295 return kAlternateStyleSideInset -
296 AlternateFrameCaptionButton::GetXOverlap();
297 }
298 return 0;
299 }
300
301 void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender,
302 const ui::Event& event) {
303 // When shift-clicking, slow down animations for visual debugging.
304 // We used to do this via an event filter that looked for the shift key being
305 // pressed but this interfered with several normal keyboard shortcuts.
306 scoped_ptr<ui::ScopedAnimationDurationScaleMode> slow_duration_mode;
307 if (event.IsShiftDown()) {
308 slow_duration_mode.reset(new ui::ScopedAnimationDurationScaleMode(
309 ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
310 }
311
312 ash::UserMetricsAction action =
313 ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE;
314 if (sender == minimize_button_) {
315 // The minimize button may move out from under the cursor.
316 ResetWindowControls();
317 frame_->Minimize();
318 } else if (sender == size_button_) {
319 // The size button may move out from under the cursor.
320 ResetWindowControls();
321 if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen.
322 frame_->SetFullscreen(false);
323 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN;
324 } else if (frame_->IsMaximized()) {
325 frame_->Restore();
326 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE;
327 } else {
328 frame_->Maximize();
329 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE;
330 }
331 } else if(sender == close_button_) {
332 frame_->Close();
333 action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK;
334 } else {
335 return;
336 }
337 ash::Shell::GetInstance()->delegate()->RecordUserMetricsAction(action);
338 }
339
340 void FrameCaptionButtonContainerView::SetButtonImages(
341 views::CustomButton* button,
342 int normal_image_id,
343 int hot_image_id,
344 int pushed_image_id) {
345 // When using the alternate button style, |button| does not inherit from
346 // views::ImageButton.
347 DCHECK(!switches::UseAlternateFrameCaptionButtonStyle());
348 views::ImageButton* image_button = static_cast<views::ImageButton*>(button);
349 ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
350 image_button->SetImage(views::CustomButton::STATE_NORMAL,
351 resource_bundle.GetImageSkiaNamed(normal_image_id));
352 image_button->SetImage(views::CustomButton::STATE_HOVERED,
353 resource_bundle.GetImageSkiaNamed(hot_image_id));
354 image_button->SetImage(views::CustomButton::STATE_PRESSED,
355 resource_bundle.GetImageSkiaNamed(pushed_image_id));
356 }
357
358 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698