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.
5 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
7 #include "base/command_line.h"
8 #include "chrome/browser/profiles/profiles_state.h"
9 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
10 #include "chrome/browser/ui/views/tabs/tab_strip.h"
11 #include "chrome/common/chrome_switches.h"
12 #include "components/signin/core/common/profile_management_switches.h"
13 #include "ui/gfx/font.h"
14 #include "ui/views/controls/button/image_button.h"
15 #include "ui/views/controls/label.h"
17 #if defined(ENABLE_SUPERVISED_USERS)
18 #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h"
23 // Besides the frame border, there's another 9 px of empty space atop the
24 // window in restored mode, to use to drag the window around.
25 const int kNonClientRestoredExtraThickness
= 9;
27 // The titlebar never shrinks too short to show the caption button plus some
29 const int kCaptionButtonHeightWithPadding
= 19;
31 // There is a 5 px gap between the title text and the caption buttons.
32 const int kTitleLogoSpacing
= 5;
34 // The frame border is only visible in restored mode and is hardcoded to 4 px on
35 // each side regardless of the system window border size.
36 const int kFrameBorderThickness
= 4;
38 // The titlebar has a 2 px 3D edge along the top and bottom.
39 const int kTitlebarTopAndBottomEdgeThickness
= 2;
41 // The icon is inset 2 px from the left frame border.
42 const int kIconLeftSpacing
= 2;
44 // There is a 4 px gap between the icon and the title text.
45 const int kIconTitleSpacing
= 4;
47 // The avatar ends 2 px above the bottom of the tabstrip (which, given the
48 // way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
50 const int kAvatarBottomSpacing
= 2;
52 // Space between the frame border and the edge of the avatar.
53 const int kAvatarOuterSpacing
= 2;
55 // Space between the edge of the avatar and the tabstrip.
56 const int kAvatarInnerSpacing
= 4;
58 #if defined(ENABLE_SUPERVISED_USERS)
59 // Space between the trailing edge of the avatar label and the tabstrip.
60 const int kSupervisedUserAvatarLabelInnerSpacing
= 10;
63 // How far the new avatar button is from the closest caption button.
64 const int kNewAvatarButtonOffset
= 5;
66 // When the title bar is in its normal two row mode (usually the case for
67 // restored windows), the New Tab button isn't at the same height as the caption
68 // buttons, but the space will look cluttered if it actually slides under them,
69 // so we stop it when the gap between the two is down to 5 px.
70 const int kNewTabCaptionNormalSpacing
= 5;
72 // When the title bar is condensed to one row (as when maximized), the New Tab
73 // button and the caption buttons are at similar vertical coordinates, so we
74 // need to reserve a larger, 16 px gap to avoid looking too cluttered.
75 const int kNewTabCaptionCondensedSpacing
= 16;
77 // If there are no caption buttons to the right of the New Tab button, we
78 // reserve a small 5px gap, regardless of whether the window is maximized. This
79 // overrides the two previous constants.
80 const int kNewTabNoCaptionButtonsSpacing
= 5;
82 // The top 3 px of the tabstrip is shadow; in maximized mode we push this off
83 // the top of the screen so the tabs appear flush against the screen edge.
84 const int kTabstripTopShadowThickness
= 3;
86 // How far to indent the tabstrip from the left side of the screen when there
88 const int kTabStripIndent
= -6;
90 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
91 // Default extra space between the top of the frame and the top of the window
93 const int kExtraCaption
= 2;
95 // Default extra spacing between individual window caption buttons.
96 const int kCaptionButtonSpacing
= 2;
98 const int kExtraCaption
= 0;
99 const int kCaptionButtonSpacing
= 0;
104 ///////////////////////////////////////////////////////////////////////////////
105 // OpaqueBrowserFrameView, public:
107 OpaqueBrowserFrameViewLayout::OpaqueBrowserFrameViewLayout(
108 OpaqueBrowserFrameViewLayoutDelegate
* delegate
)
109 : delegate_(delegate
),
110 leading_button_start_(0),
111 trailing_button_start_(0),
112 minimum_size_for_buttons_(0),
113 has_leading_buttons_(false),
114 has_trailing_buttons_(false),
115 extra_caption_y_(kExtraCaption
),
116 window_caption_spacing_(kCaptionButtonSpacing
),
117 minimize_button_(nullptr),
118 maximize_button_(nullptr),
119 restore_button_(nullptr),
120 close_button_(nullptr),
121 window_icon_(nullptr),
122 window_title_(nullptr),
123 #if defined(ENABLE_SUPERVISED_USERS)
124 supervised_user_avatar_label_(nullptr),
126 avatar_button_(nullptr),
127 new_avatar_button_(nullptr) {
128 trailing_buttons_
.push_back(views::FRAME_BUTTON_MINIMIZE
);
129 trailing_buttons_
.push_back(views::FRAME_BUTTON_MAXIMIZE
);
130 trailing_buttons_
.push_back(views::FRAME_BUTTON_CLOSE
);
133 OpaqueBrowserFrameViewLayout::~OpaqueBrowserFrameViewLayout() {}
135 void OpaqueBrowserFrameViewLayout::SetButtonOrdering(
136 const std::vector
<views::FrameButton
>& leading_buttons
,
137 const std::vector
<views::FrameButton
>& trailing_buttons
) {
138 leading_buttons_
= leading_buttons
;
139 trailing_buttons_
= trailing_buttons
;
142 gfx::Rect
OpaqueBrowserFrameViewLayout::GetBoundsForTabStrip(
143 const gfx::Size
& tabstrip_preferred_size
,
144 int available_width
) const {
145 available_width
-= trailing_button_start_
;
146 available_width
-= leading_button_start_
;
148 const int caption_spacing
= NewTabCaptionSpacing();
149 const int tabstrip_width
= available_width
- caption_spacing
;
150 gfx::Rect
bounds(leading_button_start_
, GetTabStripInsetsTop(false),
151 std::max(0, tabstrip_width
),
152 tabstrip_preferred_size
.height());
154 int leading_tabstrip_indent
= kTabStripIndent
;
155 if (delegate_
->ShouldShowAvatar() && !ShouldAvatarBeOnRight()) {
156 #if defined(ENABLE_SUPERVISED_USERS)
157 if (supervised_user_avatar_label_
&&
158 supervised_user_avatar_label_
->bounds().width())
159 leading_tabstrip_indent
+= kSupervisedUserAvatarLabelInnerSpacing
;
161 leading_tabstrip_indent
+= kAvatarInnerSpacing
;
163 leading_tabstrip_indent
+= kAvatarInnerSpacing
;
166 bounds
.Inset(leading_tabstrip_indent
, 0, 0, 0);
170 gfx::Size
OpaqueBrowserFrameViewLayout::GetMinimumSize(
171 int available_width
) const {
172 gfx::Size min_size
= delegate_
->GetBrowserViewMinimumSize();
173 int border_thickness
= NonClientBorderThickness();
174 min_size
.Enlarge(2 * border_thickness
,
175 NonClientTopBorderHeight(false) + border_thickness
);
177 // Ensure that we can, at minimum, hold our window controls and avatar icon.
178 min_size
.set_width(std::max(min_size
.width(), minimum_size_for_buttons_
));
180 // Ensure that the minimum width is enough to hold a minimum width tab strip
181 // at its usual insets.
182 if (delegate_
->IsTabStripVisible()) {
183 gfx::Size preferred_size
= delegate_
->GetTabstripPreferredSize();
184 const int min_tabstrip_width
= preferred_size
.width();
185 const int caption_spacing
= NewTabCaptionSpacing();
186 min_size
.Enlarge(min_tabstrip_width
+ caption_spacing
, 0);
192 gfx::Rect
OpaqueBrowserFrameViewLayout::GetWindowBoundsForClientBounds(
193 const gfx::Rect
& client_bounds
) const {
194 int top_height
= NonClientTopBorderHeight(false);
195 int border_thickness
= NonClientBorderThickness();
196 return gfx::Rect(std::max(0, client_bounds
.x() - border_thickness
),
197 std::max(0, client_bounds
.y() - top_height
),
198 client_bounds
.width() + (2 * border_thickness
),
199 client_bounds
.height() + top_height
+ border_thickness
);
202 int OpaqueBrowserFrameViewLayout::FrameBorderThickness(bool restored
) const {
203 return (!restored
&& (IsTitleBarCondensed() ||
204 delegate_
->IsFullscreen())) ?
205 0 : kFrameBorderThickness
;
208 int OpaqueBrowserFrameViewLayout::NonClientBorderThickness() const {
209 // When we fill the screen, we don't show a client edge.
210 return FrameBorderThickness(false) +
211 ((IsTitleBarCondensed() || delegate_
->IsFullscreen()) ?
212 0 : views::NonClientFrameView::kClientEdgeThickness
);
215 int OpaqueBrowserFrameViewLayout::NonClientTopBorderHeight(
216 bool restored
) const {
217 if (delegate_
->ShouldShowWindowTitle()) {
218 return std::max(FrameBorderThickness(restored
) + delegate_
->GetIconSize(),
219 CaptionButtonY(restored
) + kCaptionButtonHeightWithPadding
) +
220 TitlebarBottomThickness(restored
);
223 int thickness
= FrameBorderThickness(restored
);
224 if (!restored
&& delegate_
->IsTabStripVisible() &&
225 (!delegate_
->ShouldLeaveOffsetNearTopBorder() || IsTitleBarCondensed())) {
226 thickness
-= kTabstripTopShadowThickness
;
231 int OpaqueBrowserFrameViewLayout::GetTabStripInsetsTop(bool restored
) const {
232 return NonClientTopBorderHeight(restored
) + ((!restored
&&
233 (!delegate_
->ShouldLeaveOffsetNearTopBorder() ||
234 IsTitleBarCondensed() ||
235 delegate_
->IsFullscreen())) ?
236 0 : kNonClientRestoredExtraThickness
);
239 int OpaqueBrowserFrameViewLayout::TitlebarBottomThickness(bool restored
) const {
240 return kTitlebarTopAndBottomEdgeThickness
+
241 ((!restored
&& IsTitleBarCondensed()) ? 0 :
242 views::NonClientFrameView::kClientEdgeThickness
);
245 int OpaqueBrowserFrameViewLayout::CaptionButtonY(bool restored
) const {
246 // Maximized buttons start at window top, since the window has no border. This
247 // offset is for the image (the actual clickable bounds extend all the way to
248 // the top to take Fitts' Law into account).
249 return ((!restored
&& IsTitleBarCondensed()) ?
250 FrameBorderThickness(false) :
251 views::NonClientFrameView::kFrameShadowThickness
) + extra_caption_y_
;
254 gfx::Rect
OpaqueBrowserFrameViewLayout::IconBounds() const {
255 return window_icon_bounds_
;
258 gfx::Rect
OpaqueBrowserFrameViewLayout::CalculateClientAreaBounds(
261 int top_height
= NonClientTopBorderHeight(false);
262 int border_thickness
= NonClientBorderThickness();
263 return gfx::Rect(border_thickness
, top_height
,
264 std::max(0, width
- (2 * border_thickness
)),
265 std::max(0, height
- top_height
- border_thickness
));
268 bool OpaqueBrowserFrameViewLayout::IsTitleBarCondensed() const {
269 // If there are no caption buttons, there is no need to have an uncondensed
270 // title bar. If the window is maximized, the title bar is condensed
271 // regardless of whether there are caption buttons.
272 return !delegate_
->ShouldShowCaptionButtons() || delegate_
->IsMaximized();
275 ///////////////////////////////////////////////////////////////////////////////
276 // OpaqueBrowserFrameView, private:
278 bool OpaqueBrowserFrameViewLayout::ShouldAvatarBeOnRight() const {
279 // The avatar should be shown either on the end of the left or the beginning
280 // of the right depending on which side has fewer buttons.
281 return trailing_buttons_
.size() < leading_buttons_
.size();
284 int OpaqueBrowserFrameViewLayout::NewTabCaptionSpacing() const {
285 return has_trailing_buttons_
286 ? (IsTitleBarCondensed() ? kNewTabCaptionCondensedSpacing
287 : kNewTabCaptionNormalSpacing
)
288 : kNewTabNoCaptionButtonsSpacing
;
291 void OpaqueBrowserFrameViewLayout::LayoutWindowControls(views::View
* host
) {
292 int caption_y
= CaptionButtonY(false);
294 // Keep a list of all buttons that we don't show.
295 std::vector
<views::FrameButton
> buttons_not_shown
;
296 buttons_not_shown
.push_back(views::FRAME_BUTTON_MAXIMIZE
);
297 buttons_not_shown
.push_back(views::FRAME_BUTTON_MINIMIZE
);
298 buttons_not_shown
.push_back(views::FRAME_BUTTON_CLOSE
);
300 if (delegate_
->ShouldShowCaptionButtons()) {
301 for (std::vector
<views::FrameButton
>::const_iterator it
=
302 leading_buttons_
.begin(); it
!= leading_buttons_
.end(); ++it
) {
303 ConfigureButton(host
, *it
, ALIGN_LEADING
, caption_y
);
304 buttons_not_shown
.erase(
305 std::remove(buttons_not_shown
.begin(), buttons_not_shown
.end(), *it
),
306 buttons_not_shown
.end());
309 for (std::vector
<views::FrameButton
>::const_reverse_iterator it
=
310 trailing_buttons_
.rbegin(); it
!= trailing_buttons_
.rend(); ++it
) {
311 ConfigureButton(host
, *it
, ALIGN_TRAILING
, caption_y
);
312 buttons_not_shown
.erase(
313 std::remove(buttons_not_shown
.begin(), buttons_not_shown
.end(), *it
),
314 buttons_not_shown
.end());
318 for (std::vector
<views::FrameButton
>::const_iterator it
=
319 buttons_not_shown
.begin(); it
!= buttons_not_shown
.end(); ++it
) {
324 void OpaqueBrowserFrameViewLayout::LayoutTitleBar(views::View
* host
) {
325 bool use_hidden_icon_location
= true;
327 int size
= delegate_
->GetIconSize();
328 int frame_thickness
= FrameBorderThickness(false);
329 bool should_show_icon
= delegate_
->ShouldShowWindowIcon() && window_icon_
;
330 bool should_show_title
= delegate_
->ShouldShowWindowTitle() && window_title_
;
332 if (should_show_icon
|| should_show_title
) {
333 use_hidden_icon_location
= false;
335 // Our frame border has a different "3D look" than Windows'. Theirs has
336 // a more complex gradient on the top that they push their icon/title
337 // below; then the maximized window cuts this off and the icon/title are
338 // centered in the remaining space. Because the apparent shape of our
339 // border is simpler, using the same positioning makes things look
340 // slightly uncentered with restored windows, so when the window is
341 // restored, instead of calculating the remaining space from below the
342 // frame border, we calculate from below the 3D edge.
343 int unavailable_px_at_top
= IsTitleBarCondensed() ?
344 frame_thickness
: kTitlebarTopAndBottomEdgeThickness
;
345 // When the icon is shorter than the minimum space we reserve for the
346 // caption button, we vertically center it. We want to bias rounding to
347 // put extra space above the icon, since the 3D edge (+ client edge, for
348 // restored windows) below looks (to the eye) more like additional space
349 // than does the 3D edge (or nothing at all, for maximized windows)
350 // above; hence the +1.
351 int y
= unavailable_px_at_top
+ (NonClientTopBorderHeight(false) -
352 unavailable_px_at_top
- size
-
353 TitlebarBottomThickness(false) + 1) / 2;
355 window_icon_bounds_
= gfx::Rect(leading_button_start_
+ kIconLeftSpacing
, y
,
357 leading_button_start_
+= size
+ kIconLeftSpacing
;
358 minimum_size_for_buttons_
+= size
+ kIconLeftSpacing
;
361 if (should_show_icon
)
362 window_icon_
->SetBoundsRect(window_icon_bounds_
);
365 window_title_
->SetVisible(should_show_title
);
366 if (should_show_title
) {
367 window_title_
->SetText(delegate_
->GetWindowTitle());
369 int text_width
= std::max(
370 0, host
->width() - trailing_button_start_
- kTitleLogoSpacing
-
371 leading_button_start_
- kIconTitleSpacing
);
372 window_title_
->SetBounds(leading_button_start_
+ kIconTitleSpacing
,
373 window_icon_bounds_
.y(),
374 text_width
, window_icon_bounds_
.height());
375 leading_button_start_
+= text_width
+ kIconTitleSpacing
;
379 if (use_hidden_icon_location
) {
380 if (has_leading_buttons_
) {
381 // There are window button icons on the left. Don't size the hidden window
382 // icon that people can double click on to close the window.
383 window_icon_bounds_
= gfx::Rect();
385 // We set the icon bounds to a small rectangle in the top leading corner
386 // if there are no icons on the leading side.
387 window_icon_bounds_
= gfx::Rect(
388 frame_thickness
+ kIconLeftSpacing
, frame_thickness
, size
, size
);
393 void OpaqueBrowserFrameViewLayout::LayoutNewStyleAvatar(views::View
* host
) {
394 DCHECK(switches::IsNewAvatarMenu());
395 if (!new_avatar_button_
)
398 int button_width
= new_avatar_button_
->GetPreferredSize().width();
399 int button_width_with_offset
= button_width
+ kNewAvatarButtonOffset
;
402 host
->width() - trailing_button_start_
- button_width_with_offset
;
403 int button_y
= CaptionButtonY(!IsTitleBarCondensed());
405 minimum_size_for_buttons_
+= button_width_with_offset
;
406 trailing_button_start_
+= button_width_with_offset
;
408 // In non-maximized mode, allow the new tab button to completely slide under
409 // the avatar button.
410 if (!IsTitleBarCondensed()) {
411 trailing_button_start_
-=
412 TabStrip::kNewTabButtonAssetWidth
+ kNewTabCaptionNormalSpacing
;
415 // Do not include the 1px padding that is added for the caption buttons.
416 new_avatar_button_
->SetBounds(
417 button_x
, button_y
, button_width
, kCaptionButtonHeightWithPadding
- 1);
420 void OpaqueBrowserFrameViewLayout::LayoutAvatar(views::View
* host
) {
421 // Even though the avatar is used for both incognito and profiles we always
422 // use the incognito icon to layout the avatar button. The profile icon
423 // can be customized so we can't depend on its size to perform layout.
424 gfx::ImageSkia incognito_icon
= delegate_
->GetOTRAvatarIcon();
426 bool avatar_on_right
= ShouldAvatarBeOnRight();
427 int avatar_bottom
= GetTabStripInsetsTop(false) +
428 delegate_
->GetTabStripHeight() - kAvatarBottomSpacing
;
429 int avatar_restored_y
= avatar_bottom
- incognito_icon
.height();
430 int avatar_x
= avatar_on_right
?
431 host
->width() - trailing_button_start_
- kAvatarOuterSpacing
-
432 incognito_icon
.width() :
433 leading_button_start_
+ kAvatarOuterSpacing
;
434 int avatar_y
= IsTitleBarCondensed() ?
435 (NonClientTopBorderHeight(false) + kTabstripTopShadowThickness
) :
437 avatar_bounds_
.SetRect(
440 incognito_icon
.width(),
441 delegate_
->ShouldShowAvatar() ? (avatar_bottom
- avatar_y
) : 0);
442 if (avatar_button_
) {
443 avatar_button_
->set_button_on_right(avatar_on_right
);
444 avatar_button_
->SetBoundsRect(avatar_bounds_
);
447 #if defined(ENABLE_SUPERVISED_USERS)
448 if (supervised_user_avatar_label_
) {
449 supervised_user_avatar_label_
->SetLabelOnRight(avatar_on_right
);
450 // Space between the bottom of the avatar and the bottom of the avatar
452 const int kSupervisedUserAvatarLabelBottomSpacing
= 3;
453 gfx::Size label_size
= supervised_user_avatar_label_
->GetPreferredSize();
454 // The outside edge of the avatar label should be just outside that of the
455 // avatar menu button.
456 int avatar_label_x
= avatar_on_right
?
457 (host
->width() - trailing_button_start_
- label_size
.width()) :
458 leading_button_start_
;
459 gfx::Rect
label_bounds(
461 avatar_bottom
- kSupervisedUserAvatarLabelBottomSpacing
-
464 delegate_
->ShouldShowAvatar() ? label_size
.height() : 0);
465 supervised_user_avatar_label_
->SetBoundsRect(label_bounds
);
466 edge_offset
= label_size
.width();
468 edge_offset
= kAvatarOuterSpacing
+ incognito_icon
.width();
471 edge_offset
= kAvatarOuterSpacing
+ incognito_icon
.width();
474 trailing_button_start_
+= edge_offset
;
476 leading_button_start_
+= edge_offset
;
478 // We just add the avatar button size to the minimum size because clicking
479 // the avatar label does the same thing as clicking the avatar button.
480 minimum_size_for_buttons_
+= kAvatarOuterSpacing
+ incognito_icon
.width();
484 void OpaqueBrowserFrameViewLayout::ConfigureButton(
486 views::FrameButton button_id
,
487 ButtonAlignment alignment
,
490 case views::FRAME_BUTTON_MINIMIZE
: {
491 minimize_button_
->SetVisible(true);
492 SetBoundsForButton(host
, minimize_button_
, alignment
, caption_y
);
495 case views::FRAME_BUTTON_MAXIMIZE
: {
496 // When the window is restored, we show a maximized button; otherwise, we
497 // show a restore button.
498 bool is_restored
= !delegate_
->IsMaximized() && !delegate_
->IsMinimized();
499 views::ImageButton
* invisible_button
= is_restored
?
500 restore_button_
: maximize_button_
;
501 invisible_button
->SetVisible(false);
503 views::ImageButton
* visible_button
= is_restored
?
504 maximize_button_
: restore_button_
;
505 visible_button
->SetVisible(true);
506 SetBoundsForButton(host
, visible_button
, alignment
, caption_y
);
509 case views::FRAME_BUTTON_CLOSE
: {
510 close_button_
->SetVisible(true);
511 SetBoundsForButton(host
, close_button_
, alignment
, caption_y
);
517 void OpaqueBrowserFrameViewLayout::HideButton(views::FrameButton button_id
) {
519 case views::FRAME_BUTTON_MINIMIZE
:
520 minimize_button_
->SetVisible(false);
522 case views::FRAME_BUTTON_MAXIMIZE
:
523 restore_button_
->SetVisible(false);
524 maximize_button_
->SetVisible(false);
526 case views::FRAME_BUTTON_CLOSE
:
527 close_button_
->SetVisible(false);
532 void OpaqueBrowserFrameViewLayout::SetBoundsForButton(
534 views::ImageButton
* button
,
535 ButtonAlignment alignment
,
537 gfx::Size button_size
= button
->GetPreferredSize();
539 button
->SetImageAlignment(
540 (alignment
== ALIGN_LEADING
) ?
541 views::ImageButton::ALIGN_RIGHT
: views::ImageButton::ALIGN_LEFT
,
542 views::ImageButton::ALIGN_BOTTOM
);
544 // There should always be the same number of non-shadow pixels visible to the
545 // side of the caption buttons. In maximized mode we extend buttons to the
546 // screen top and the rightmost button to the screen right (or leftmost button
547 // to the screen left, for left-aligned buttons) to obey Fitts' Law.
548 bool title_bar_condensed
= IsTitleBarCondensed();
550 // When we are the first button on the leading side and are the close
551 // button, we must flip ourselves, because the close button assets have
552 // a little notch to fit in the rounded frame.
553 button
->SetDrawImageMirrored(alignment
== ALIGN_LEADING
&&
554 !has_leading_buttons_
&&
555 button
== close_button_
);
556 // If the window is maximized, align the buttons to its upper edge.
557 int extra_height
= title_bar_condensed
? extra_caption_y_
: 0;
560 case ALIGN_LEADING
: {
561 if (has_leading_buttons_
)
562 leading_button_start_
+= window_caption_spacing_
;
564 // If we're the first button on the left and maximized, add width to the
565 // right hand side of the screen.
566 int extra_width
= (title_bar_condensed
&& !has_leading_buttons_
) ?
567 (kFrameBorderThickness
-
568 views::NonClientFrameView::kFrameShadowThickness
) : 0;
571 leading_button_start_
,
572 caption_y
- extra_height
,
573 button_size
.width() + extra_width
,
574 button_size
.height() + extra_height
);
576 leading_button_start_
+= extra_width
+ button_size
.width();
577 minimum_size_for_buttons_
+= extra_width
+ button_size
.width();
578 has_leading_buttons_
= true;
581 case ALIGN_TRAILING
: {
582 if (has_trailing_buttons_
)
583 trailing_button_start_
+= window_caption_spacing_
;
585 // If we're the first button on the right and maximized, add width to the
586 // right hand side of the screen.
587 int extra_width
= (title_bar_condensed
&& !has_trailing_buttons_
) ?
588 (kFrameBorderThickness
-
589 views::NonClientFrameView::kFrameShadowThickness
) : 0;
592 host
->width() - trailing_button_start_
- extra_width
-
594 caption_y
- extra_height
,
595 button_size
.width() + extra_width
,
596 button_size
.height() + extra_height
);
598 trailing_button_start_
+= extra_width
+ button_size
.width();
599 minimum_size_for_buttons_
+= extra_width
+ button_size
.width();
600 has_trailing_buttons_
= true;
606 void OpaqueBrowserFrameViewLayout::SetView(int id
, views::View
* view
) {
607 // Why do things this way instead of having an Init() method, where we're
608 // passed the views we'll handle? Because OpaqueBrowserFrameView doesn't own
609 // all the views which are part of it. The avatar stuff, for example, will be
610 // added and removed by the base class of OpaqueBrowserFrameView.
612 case VIEW_ID_MINIMIZE_BUTTON
:
614 DCHECK_EQ(std::string(views::ImageButton::kViewClassName
),
615 view
->GetClassName());
617 minimize_button_
= static_cast<views::ImageButton
*>(view
);
619 case VIEW_ID_MAXIMIZE_BUTTON
:
621 DCHECK_EQ(std::string(views::ImageButton::kViewClassName
),
622 view
->GetClassName());
624 maximize_button_
= static_cast<views::ImageButton
*>(view
);
626 case VIEW_ID_RESTORE_BUTTON
:
628 DCHECK_EQ(std::string(views::ImageButton::kViewClassName
),
629 view
->GetClassName());
631 restore_button_
= static_cast<views::ImageButton
*>(view
);
633 case VIEW_ID_CLOSE_BUTTON
:
635 DCHECK_EQ(std::string(views::ImageButton::kViewClassName
),
636 view
->GetClassName());
638 close_button_
= static_cast<views::ImageButton
*>(view
);
640 case VIEW_ID_WINDOW_ICON
:
643 case VIEW_ID_WINDOW_TITLE
:
645 DCHECK_EQ(std::string(views::Label::kViewClassName
),
646 view
->GetClassName());
648 window_title_
= static_cast<views::Label
*>(view
);
650 #if defined(ENABLE_SUPERVISED_USERS)
651 case VIEW_ID_SUPERVISED_USER_AVATAR_LABEL
:
652 supervised_user_avatar_label_
=
653 static_cast<SupervisedUserAvatarLabel
*>(view
);
656 case VIEW_ID_AVATAR_BUTTON
:
658 DCHECK_EQ(std::string(AvatarMenuButton::kViewClassName
),
659 view
->GetClassName());
661 avatar_button_
= static_cast<AvatarMenuButton
*>(view
);
663 case VIEW_ID_NEW_AVATAR_BUTTON
:
664 new_avatar_button_
= view
;
667 NOTIMPLEMENTED() << "Unknown view id " << id
;
672 ///////////////////////////////////////////////////////////////////////////////
673 // OpaqueBrowserFrameView, views::LayoutManager:
675 void OpaqueBrowserFrameViewLayout::Layout(views::View
* host
) {
676 // Reset all our data so that everything is invisible.
677 int thickness
= FrameBorderThickness(false);
678 leading_button_start_
= thickness
;
679 trailing_button_start_
= thickness
;
680 minimum_size_for_buttons_
= leading_button_start_
+ trailing_button_start_
;
681 has_leading_buttons_
= false;
682 has_trailing_buttons_
= false;
684 LayoutWindowControls(host
);
685 LayoutTitleBar(host
);
687 // We now add a single pixel to the leading spacing. We do this because the
688 // avatar and tab strip start one pixel inward compared to where things start
689 // on the trailing side.
690 leading_button_start_
++;
692 if (delegate_
->IsRegularOrGuestSession() && switches::IsNewAvatarMenu())
693 LayoutNewStyleAvatar(host
);
697 client_view_bounds_
= CalculateClientAreaBounds(
698 host
->width(), host
->height());
701 gfx::Size
OpaqueBrowserFrameViewLayout::GetPreferredSize(
702 const views::View
* host
) const {
703 // This is never used; NonClientView::GetPreferredSize() will be called
709 void OpaqueBrowserFrameViewLayout::ViewAdded(views::View
* host
,
711 SetView(view
->id(), view
);
714 void OpaqueBrowserFrameViewLayout::ViewRemoved(views::View
* host
,
716 SetView(view
->id(), nullptr);