opaque_browser_frame_view_layout.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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 "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
6
7#include "chrome/browser/profiles/profiles_state.h"
8#include "chrome/browser/ui/views/new_avatar_button.h"
9#include "ui/gfx/font.h"
10#include "ui/views/controls/button/image_button.h"
11#include "ui/views/controls/label.h"
12
13#if defined(OS_WIN)
14#include "win8/util/win8_util.h"
15#endif  // OS_WIN
16
17namespace {
18
19// Besides the frame border, there's another 9 px of empty space atop the
20// window in restored mode, to use to drag the window around.
21const int kNonClientRestoredExtraThickness = 9;
22
23// The titlebar never shrinks too short to show the caption button plus some
24// padding below it.
25const int kCaptionButtonHeightWithPadding = 19;
26
27// There is a 5 px gap between the title text and the caption buttons.
28const int kTitleLogoSpacing = 5;
29
30// The frame border is only visible in restored mode and is hardcoded to 4 px on
31// each side regardless of the system window border size.
32const int kFrameBorderThickness = 4;
33
34// The titlebar has a 2 px 3D edge along the top and bottom.
35const int kTitlebarTopAndBottomEdgeThickness = 2;
36
37// The icon is inset 2 px from the left frame border.
38const int kIconLeftSpacing = 2;
39
40// There is a 4 px gap between the icon and the title text.
41const int kIconTitleSpacing = 4;
42
43// The avatar ends 2 px above the bottom of the tabstrip (which, given the
44// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
45// user).
46const int kAvatarBottomSpacing = 2;
47
48// Space between the frame border and the left edge of the avatar.
49const int kAvatarLeftSpacing = 2;
50
51// Space between the right edge of the avatar and the tabstrip.
52const int kAvatarRightSpacing = -4;
53
54// How far the new avatar button is from the closest caption button.
55const int kNewAvatarButtonOffset = 5;
56
57// In restored mode, the New Tab button isn't at the same height as the caption
58// buttons, but the space will look cluttered if it actually slides under them,
59// so we stop it when the gap between the two is down to 5 px.
60const int kNewTabCaptionRestoredSpacing = 5;
61
62// In maximized mode, where the New Tab button and the caption buttons are at
63// similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid
64// looking too cluttered.
65const int kNewTabCaptionMaximizedSpacing = 16;
66
67// The top 3 px of the tabstrip is shadow; in maximized mode we push this off
68// the top of the screen so the tabs appear flush against the screen edge.
69const int kTabstripTopShadowThickness = 3;
70
71// How far to indent the tabstrip from the left side of the screen when there
72// is no avatar icon.
73const int kTabStripIndent = -6;
74
75#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
76// Default extra space between the top of the frame and the top of the window
77// caption buttons.
78const int kExtraCaption = 2;
79
80// Default extra spacing between individual window caption buttons.
81const int kCaptionButtonSpacing = 2;
82#else
83const int kExtraCaption = 0;
84const int kCaptionButtonSpacing = 0;
85#endif
86
87}  // namespace
88
89///////////////////////////////////////////////////////////////////////////////
90// OpaqueBrowserFrameView, public:
91
92OpaqueBrowserFrameViewLayout::OpaqueBrowserFrameViewLayout(
93    OpaqueBrowserFrameViewLayoutDelegate* delegate)
94    : delegate_(delegate),
95      leading_button_start_(0),
96      trailing_button_start_(0),
97      minimum_size_for_buttons_(0),
98      has_leading_buttons_(false),
99      has_trailing_buttons_(false),
100      extra_caption_y_(kExtraCaption),
101      window_caption_spacing_(kCaptionButtonSpacing),
102      minimize_button_(NULL),
103      maximize_button_(NULL),
104      restore_button_(NULL),
105      close_button_(NULL),
106      window_icon_(NULL),
107      window_title_(NULL),
108      avatar_label_(NULL),
109      avatar_button_(NULL),
110      new_avatar_button_(NULL) {
111  trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE);
112  trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE);
113  trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE);
114}
115
116OpaqueBrowserFrameViewLayout::~OpaqueBrowserFrameViewLayout() {}
117
118// static
119bool OpaqueBrowserFrameViewLayout::ShouldAddDefaultCaptionButtons() {
120#if defined(OS_WIN)
121  return !win8::IsSingleWindowMetroMode();
122#endif  // OS_WIN
123  return true;
124}
125
126void OpaqueBrowserFrameViewLayout::SetButtonOrdering(
127    const std::vector<views::FrameButton>& leading_buttons,
128    const std::vector<views::FrameButton>& trailing_buttons) {
129  leading_buttons_ = leading_buttons;
130  trailing_buttons_ = trailing_buttons;
131}
132
133gfx::Rect OpaqueBrowserFrameViewLayout::GetBoundsForTabStrip(
134    const gfx::Size& tabstrip_preferred_size,
135    int available_width) const {
136  available_width -= trailing_button_start_;
137  available_width -= leading_button_start_;
138
139  if (delegate_->GetAdditionalReservedSpaceInTabStrip())
140    available_width -= delegate_->GetAdditionalReservedSpaceInTabStrip();
141
142  const int caption_spacing = delegate_->IsMaximized() ?
143      kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing;
144  const int tabstrip_width = available_width - caption_spacing;
145  gfx::Rect bounds(leading_button_start_, GetTabStripInsetsTop(false),
146                   std::max(0, tabstrip_width),
147                   tabstrip_preferred_size.height());
148
149  int leading_tabstrip_indent = kTabStripIndent;
150  if (delegate_->ShouldShowAvatar()) {
151    if (avatar_label_ && avatar_label_->bounds().width()) {
152      // Space between the trailing edge of the avatar label and the tabstrip.
153      const int kAvatarLabelRightSpacing = -10;
154      leading_tabstrip_indent -= kAvatarLabelRightSpacing;
155    } else {
156      leading_tabstrip_indent -= kAvatarRightSpacing;
157    }
158  }
159  bounds.Inset(leading_tabstrip_indent, 0, 0, 0);
160  return bounds;
161}
162
163gfx::Size OpaqueBrowserFrameViewLayout::GetMinimumSize(
164    int available_width) const {
165  gfx::Size min_size = delegate_->GetBrowserViewMinimumSize();
166  int border_thickness = NonClientBorderThickness();
167  min_size.Enlarge(2 * border_thickness,
168                   NonClientTopBorderHeight(false) + border_thickness);
169
170  // Ensure that we can, at minimum, hold our window controls and avatar icon.
171  min_size.set_width(std::max(min_size.width(), minimum_size_for_buttons_));
172
173  // Ensure that the minimum width is enough to hold a minimum width tab strip
174  // at its usual insets.
175  if (delegate_->IsTabStripVisible()) {
176    gfx::Size preferred_size = delegate_->GetTabstripPreferredSize();
177    const int min_tabstrip_width = preferred_size.width();
178    const int caption_spacing = delegate_->IsMaximized() ?
179        kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing;
180    min_size.Enlarge(min_tabstrip_width + caption_spacing, 0);
181  }
182
183  return min_size;
184}
185
186gfx::Rect OpaqueBrowserFrameViewLayout::GetWindowBoundsForClientBounds(
187    const gfx::Rect& client_bounds) const {
188  int top_height = NonClientTopBorderHeight(false);
189  int border_thickness = NonClientBorderThickness();
190  return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
191                   std::max(0, client_bounds.y() - top_height),
192                   client_bounds.width() + (2 * border_thickness),
193                   client_bounds.height() + top_height + border_thickness);
194}
195
196int OpaqueBrowserFrameViewLayout::FrameBorderThickness(bool restored) const {
197  return (!restored && (delegate_->IsMaximized() ||
198                        delegate_->IsFullscreen())) ?
199      0 : kFrameBorderThickness;
200}
201
202int OpaqueBrowserFrameViewLayout::NonClientBorderThickness() const {
203  // When we fill the screen, we don't show a client edge.
204  return FrameBorderThickness(false) +
205      ((delegate_->IsMaximized() || delegate_->IsFullscreen()) ?
206       0 : views::NonClientFrameView::kClientEdgeThickness);
207}
208
209int OpaqueBrowserFrameViewLayout::NonClientTopBorderHeight(
210    bool restored) const {
211  if (delegate_->ShouldShowWindowTitle()) {
212    return std::max(FrameBorderThickness(restored) + delegate_->GetIconSize(),
213        CaptionButtonY(restored) + kCaptionButtonHeightWithPadding) +
214        TitlebarBottomThickness(restored);
215  }
216
217  return FrameBorderThickness(restored) -
218      ((delegate_->IsTabStripVisible() &&
219          !restored && !delegate_->ShouldLeaveOffsetNearTopBorder())
220              ? kTabstripTopShadowThickness : 0);
221}
222
223int OpaqueBrowserFrameViewLayout::GetTabStripInsetsTop(bool restored) const {
224  return NonClientTopBorderHeight(restored) + ((!restored &&
225      (!delegate_->ShouldLeaveOffsetNearTopBorder() ||
226      delegate_->IsFullscreen())) ?
227      0 : kNonClientRestoredExtraThickness);
228}
229
230int OpaqueBrowserFrameViewLayout::TitlebarBottomThickness(bool restored) const {
231  return kTitlebarTopAndBottomEdgeThickness +
232      ((!restored && delegate_->IsMaximized()) ? 0 :
233       views::NonClientFrameView::kClientEdgeThickness);
234}
235
236int OpaqueBrowserFrameViewLayout::CaptionButtonY(bool restored) const {
237  // Maximized buttons start at window top so that even if their images aren't
238  // drawn flush with the screen edge, they still obey Fitts' Law.
239  return ((!restored && delegate_->IsMaximized()) ?
240      FrameBorderThickness(false) :
241          views::NonClientFrameView::kFrameShadowThickness) + extra_caption_y_;
242}
243
244gfx::Rect OpaqueBrowserFrameViewLayout::IconBounds() const {
245  return window_icon_bounds_;
246}
247
248gfx::Rect OpaqueBrowserFrameViewLayout::CalculateClientAreaBounds(
249    int width,
250    int height) const {
251  int top_height = NonClientTopBorderHeight(false);
252  int border_thickness = NonClientBorderThickness();
253  return gfx::Rect(border_thickness, top_height,
254                   std::max(0, width - (2 * border_thickness)),
255                   std::max(0, height - top_height - border_thickness));
256}
257
258///////////////////////////////////////////////////////////////////////////////
259// OpaqueBrowserFrameView, private:
260
261void OpaqueBrowserFrameViewLayout::LayoutWindowControls(views::View* host) {
262  if (!ShouldAddDefaultCaptionButtons())
263    return;
264
265  int caption_y = CaptionButtonY(false);
266
267  // Keep a list of all buttons that we don't show.
268  std::vector<views::FrameButton> buttons_not_shown;
269  buttons_not_shown.push_back(views::FRAME_BUTTON_MAXIMIZE);
270  buttons_not_shown.push_back(views::FRAME_BUTTON_MINIMIZE);
271  buttons_not_shown.push_back(views::FRAME_BUTTON_CLOSE);
272
273  for (std::vector<views::FrameButton>::const_iterator it =
274           leading_buttons_.begin(); it != leading_buttons_.end(); ++it) {
275    ConfigureButton(host, *it, ALIGN_LEADING, caption_y);
276    buttons_not_shown.erase(
277        std::remove(buttons_not_shown.begin(), buttons_not_shown.end(), *it),
278        buttons_not_shown.end());
279  }
280
281  for (std::vector<views::FrameButton>::const_reverse_iterator it =
282           trailing_buttons_.rbegin(); it != trailing_buttons_.rend(); ++it) {
283    ConfigureButton(host, *it, ALIGN_TRAILING, caption_y);
284    buttons_not_shown.erase(
285        std::remove(buttons_not_shown.begin(), buttons_not_shown.end(), *it),
286        buttons_not_shown.end());
287  }
288
289  for (std::vector<views::FrameButton>::const_iterator it =
290           buttons_not_shown.begin(); it != buttons_not_shown.end(); ++it) {
291    HideButton(*it);
292  }
293}
294
295void OpaqueBrowserFrameViewLayout::LayoutTitleBar(views::View* host) {
296  bool use_hidden_icon_location = true;
297
298  int size = delegate_->GetIconSize();
299  int frame_thickness = FrameBorderThickness(false);
300  bool should_show_icon = delegate_->ShouldShowWindowIcon();
301  bool should_show_title = delegate_->ShouldShowWindowTitle();
302
303  if (should_show_icon || should_show_title) {
304    use_hidden_icon_location = false;
305
306    // Our frame border has a different "3D look" than Windows'.  Theirs has
307    // a more complex gradient on the top that they push their icon/title
308    // below; then the maximized window cuts this off and the icon/title are
309    // centered in the remaining space.  Because the apparent shape of our
310    // border is simpler, using the same positioning makes things look
311    // slightly uncentered with restored windows, so when the window is
312    // restored, instead of calculating the remaining space from below the
313    // frame border, we calculate from below the 3D edge.
314    int unavailable_px_at_top = delegate_->IsMaximized() ?
315        frame_thickness : kTitlebarTopAndBottomEdgeThickness;
316    // When the icon is shorter than the minimum space we reserve for the
317    // caption button, we vertically center it.  We want to bias rounding to
318    // put extra space above the icon, since the 3D edge (+ client edge, for
319    // restored windows) below looks (to the eye) more like additional space
320    // than does the 3D edge (or nothing at all, for maximized windows)
321    // above; hence the +1.
322    int y = unavailable_px_at_top + (NonClientTopBorderHeight(false) -
323                                     unavailable_px_at_top - size -
324                                     TitlebarBottomThickness(false) + 1) / 2;
325
326    window_icon_bounds_ = gfx::Rect(leading_button_start_ + kIconLeftSpacing, y,
327                                    size, size);
328    leading_button_start_ += size + kIconLeftSpacing;
329    minimum_size_for_buttons_ += size + kIconLeftSpacing;
330  }
331
332  if (should_show_icon)
333    window_icon_->SetBoundsRect(window_icon_bounds_);
334
335  if (window_title_) {
336    window_title_->SetVisible(should_show_title);
337    if (should_show_title) {
338      window_title_->SetText(delegate_->GetWindowTitle());
339
340      int text_width = std::max(
341          0, host->width() - trailing_button_start_ - kTitleLogoSpacing -
342          leading_button_start_ - kIconTitleSpacing);
343      window_title_->SetBounds(leading_button_start_ + kIconTitleSpacing,
344                               window_icon_bounds_.y(),
345                               text_width, window_icon_bounds_.height());
346      leading_button_start_ += text_width + kIconTitleSpacing;
347    }
348  }
349
350  if (use_hidden_icon_location) {
351    if (has_leading_buttons_) {
352      // There are window button icons on the left. Don't size the hidden window
353      // icon that people can double click on to close the window.
354      window_icon_bounds_ = gfx::Rect();
355    } else {
356      // We set the icon bounds to a small rectangle in the top leading corner
357      // if there are no icons on the leading side.
358      window_icon_bounds_ = gfx::Rect(
359          frame_thickness + kIconLeftSpacing, frame_thickness, size, size);
360    }
361  }
362}
363
364void OpaqueBrowserFrameViewLayout::LayoutNewStyleAvatar(views::View* host) {
365  gfx::Size label_size = new_avatar_button_->GetPreferredSize();
366  int button_size_with_offset = kNewAvatarButtonOffset + label_size.width();
367
368  int button_x = host->width() - trailing_button_start_ -
369      button_size_with_offset;
370  int button_y = CaptionButtonY(false);
371
372  trailing_button_start_ += button_size_with_offset;
373  minimum_size_for_buttons_ += button_size_with_offset;
374
375  new_avatar_button_->SetBounds(
376      button_x,
377      button_y,
378      label_size.width(),
379      button_y + kCaptionButtonHeightWithPadding);
380}
381
382void OpaqueBrowserFrameViewLayout::LayoutAvatar() {
383  // Even though the avatar is used for both incognito and profiles we always
384  // use the incognito icon to layout the avatar button. The profile icon
385  // can be customized so we can't depend on its size to perform layout.
386  gfx::ImageSkia incognito_icon = delegate_->GetOTRAvatarIcon();
387
388  int avatar_bottom = GetTabStripInsetsTop(false) +
389      delegate_->GetTabStripHeight() - kAvatarBottomSpacing;
390  int avatar_restored_y = avatar_bottom - incognito_icon.height();
391  int avatar_y = delegate_->IsMaximized() ?
392      (NonClientTopBorderHeight(false) + kTabstripTopShadowThickness) :
393      avatar_restored_y;
394  avatar_bounds_.SetRect(leading_button_start_ + kAvatarLeftSpacing,
395      avatar_y, incognito_icon.width(),
396      delegate_->ShouldShowAvatar() ? (avatar_bottom - avatar_y) : 0);
397  if (avatar_button_) {
398    avatar_button_->SetBoundsRect(avatar_bounds_);
399
400    if (avatar_label_) {
401      // Space between the bottom of the avatar and the bottom of the avatar
402      // label.
403      const int kAvatarLabelBottomSpacing = 3;
404      gfx::Size label_size = avatar_label_->GetPreferredSize();
405      // The x-position of the avatar label should be slightly to the left of
406      // the avatar menu button. Therefore we use the |leading_button_start_|
407      // value directly.
408      gfx::Rect label_bounds(
409          leading_button_start_,
410          avatar_bottom - kAvatarLabelBottomSpacing - label_size.height(),
411          label_size.width(),
412          delegate_->ShouldShowAvatar() ? label_size.height() : 0);
413      avatar_label_->SetBoundsRect(label_bounds);
414      leading_button_start_ += label_size.width();
415    } else {
416      leading_button_start_ += kAvatarLeftSpacing + incognito_icon.width();
417    }
418
419    // We just add the avatar button size to the minimum size because clicking
420    // the avatar label does the same thing as clicking the avatar button.
421    minimum_size_for_buttons_ += kAvatarLeftSpacing + incognito_icon.width();
422  }
423}
424
425void OpaqueBrowserFrameViewLayout::ConfigureButton(
426    views::View* host,
427    views::FrameButton button_id,
428    ButtonAlignment alignment,
429    int caption_y) {
430  switch (button_id) {
431    case views::FRAME_BUTTON_MINIMIZE: {
432      minimize_button_->SetVisible(true);
433      SetBoundsForButton(host, minimize_button_, alignment, caption_y);
434      break;
435    }
436    case views::FRAME_BUTTON_MAXIMIZE: {
437      // When the window is restored, we show a maximized button; otherwise, we
438      // show a restore button.
439      bool is_restored = !delegate_->IsMaximized() && !delegate_->IsMinimized();
440      views::ImageButton* invisible_button = is_restored ?
441          restore_button_ : maximize_button_;
442      invisible_button->SetVisible(false);
443
444      views::ImageButton* visible_button = is_restored ?
445          maximize_button_ : restore_button_;
446      visible_button->SetVisible(true);
447      SetBoundsForButton(host, visible_button, alignment, caption_y);
448      break;
449    }
450    case views::FRAME_BUTTON_CLOSE: {
451      close_button_->SetVisible(true);
452      SetBoundsForButton(host, close_button_, alignment, caption_y);
453      break;
454    }
455  }
456}
457
458void OpaqueBrowserFrameViewLayout::HideButton(views::FrameButton button_id) {
459  switch (button_id) {
460    case views::FRAME_BUTTON_MINIMIZE:
461      minimize_button_->SetVisible(false);
462      break;
463    case views::FRAME_BUTTON_MAXIMIZE:
464      restore_button_->SetVisible(false);
465      maximize_button_->SetVisible(false);
466      break;
467    case views::FRAME_BUTTON_CLOSE:
468      close_button_->SetVisible(false);
469      break;
470  }
471}
472
473void OpaqueBrowserFrameViewLayout::SetBoundsForButton(
474    views::View* host,
475    views::ImageButton* button,
476    ButtonAlignment alignment,
477    int caption_y) {
478  gfx::Size button_size = button->GetPreferredSize();
479
480  button->SetImageAlignment(
481      (alignment == ALIGN_LEADING)  ?
482          views::ImageButton::ALIGN_RIGHT : views::ImageButton::ALIGN_LEFT,
483      views::ImageButton::ALIGN_BOTTOM);
484
485  // There should always be the same number of non-shadow pixels visible to the
486  // side of the caption buttons.  In maximized mode we extend the rightmost
487  // button to the screen corner to obey Fitts' Law.
488  bool is_maximized = delegate_->IsMaximized();
489
490  // When we are the first button on the leading side and are the close
491  // button, we must flip ourselves, because the close button assets have
492  // a little notch to fit in the rounded frame.
493  button->SetDrawImageMirrored(alignment == ALIGN_LEADING &&
494                               !has_leading_buttons_ &&
495                               button == close_button_);
496
497  switch (alignment) {
498    case ALIGN_LEADING: {
499      if (has_leading_buttons_)
500        leading_button_start_ += window_caption_spacing_;
501
502      // If we're the first button on the left and maximized, add with to the
503      // right hand side of the screen.
504      int extra_width = (is_maximized && !has_leading_buttons_) ?
505        (kFrameBorderThickness -
506         views::NonClientFrameView::kFrameShadowThickness) : 0;
507
508      button->SetBounds(
509          leading_button_start_ - extra_width,
510          caption_y,
511          button_size.width() + extra_width,
512          button_size.height());
513
514      leading_button_start_ += extra_width + button_size.width();
515      minimum_size_for_buttons_ += extra_width + button_size.width();
516      has_leading_buttons_ = true;
517      break;
518    }
519    case ALIGN_TRAILING: {
520      if (has_trailing_buttons_)
521        trailing_button_start_ += window_caption_spacing_;
522
523      // If we're the first button on the right and maximized, add with to the
524      // right hand side of the screen.
525      int extra_width = (is_maximized && !has_trailing_buttons_) ?
526        (kFrameBorderThickness -
527         views::NonClientFrameView::kFrameShadowThickness) : 0;
528
529      button->SetBounds(
530          host->width() - trailing_button_start_ - extra_width -
531              button_size.width(),
532          caption_y,
533          button_size.width() + extra_width,
534          button_size.height());
535
536      trailing_button_start_ += extra_width + button_size.width();
537      minimum_size_for_buttons_ += extra_width + button_size.width();
538      has_trailing_buttons_ = true;
539      break;
540    }
541  }
542}
543
544void OpaqueBrowserFrameViewLayout::SetView(int id, views::View* view) {
545  // Why do things this way instead of having an Init() method, where we're
546  // passed the views we'll handle? Because OpaqueBrowserFrameView doesn't own
547  // all the views which are part of it. The avatar stuff, for example, will be
548  // added and removed by the base class of OpaqueBrowserFrameView.
549  switch (id) {
550    case VIEW_ID_MINIMIZE_BUTTON:
551      if (view) {
552        DCHECK_EQ(std::string(views::ImageButton::kViewClassName),
553                  view->GetClassName());
554      }
555      minimize_button_ = static_cast<views::ImageButton*>(view);
556      break;
557    case VIEW_ID_MAXIMIZE_BUTTON:
558      if (view) {
559        DCHECK_EQ(std::string(views::ImageButton::kViewClassName),
560                  view->GetClassName());
561      }
562      maximize_button_ = static_cast<views::ImageButton*>(view);
563      break;
564    case VIEW_ID_RESTORE_BUTTON:
565      if (view) {
566        DCHECK_EQ(std::string(views::ImageButton::kViewClassName),
567                  view->GetClassName());
568      }
569      restore_button_ = static_cast<views::ImageButton*>(view);
570      break;
571    case VIEW_ID_CLOSE_BUTTON:
572      if (view) {
573        DCHECK_EQ(std::string(views::ImageButton::kViewClassName),
574                  view->GetClassName());
575      }
576      close_button_ = static_cast<views::ImageButton*>(view);
577      break;
578    case VIEW_ID_WINDOW_ICON:
579      window_icon_ = view;
580      break;
581    case VIEW_ID_WINDOW_TITLE:
582      if (view) {
583        DCHECK_EQ(std::string(views::Label::kViewClassName),
584                  view->GetClassName());
585      }
586      window_title_ = static_cast<views::Label*>(view);
587      break;
588    case VIEW_ID_AVATAR_LABEL:
589      avatar_label_ = view;
590      break;
591    case VIEW_ID_AVATAR_BUTTON:
592      avatar_button_ = view;
593      break;
594    case VIEW_ID_NEW_AVATAR_BUTTON:
595      new_avatar_button_ = static_cast<NewAvatarButton*>(view);
596      break;
597    default:
598      NOTIMPLEMENTED() << "Unknown view id " << id;
599      break;
600  }
601}
602
603///////////////////////////////////////////////////////////////////////////////
604// OpaqueBrowserFrameView, views::LayoutManager:
605
606void OpaqueBrowserFrameViewLayout::Layout(views::View* host) {
607  // Reset all our data so that everything is invisible.
608  int thickness = FrameBorderThickness(false);
609  leading_button_start_ = thickness;
610  trailing_button_start_ = thickness;
611  minimum_size_for_buttons_ = leading_button_start_ + trailing_button_start_;
612  has_leading_buttons_ = false;
613  has_trailing_buttons_ = false;
614
615  LayoutWindowControls(host);
616  LayoutTitleBar(host);
617
618  // We now add a single pixel to the leading spacing. We do this because the
619  // avatar and tab strip start one pixel inward compared to where things start
620  // on the trailing side.
621  leading_button_start_++;
622
623  if (delegate_->IsRegularOrGuestSession() &&
624      profiles::IsNewProfileManagementEnabled())
625    LayoutNewStyleAvatar(host);
626  else
627    LayoutAvatar();
628
629  client_view_bounds_ = CalculateClientAreaBounds(
630      host->width(), host->height());
631}
632
633gfx::Size OpaqueBrowserFrameViewLayout::GetPreferredSize(views::View* host) {
634  // This is never used; NonClientView::GetPreferredSize() will be called
635  // instead.
636  NOTREACHED();
637  return gfx::Size();
638}
639
640void OpaqueBrowserFrameViewLayout::ViewAdded(views::View* host,
641                                             views::View* view) {
642  SetView(view->id(), view);
643}
644
645void OpaqueBrowserFrameViewLayout::ViewRemoved(views::View* host,
646                                               views::View* view) {
647  SetView(view->id(), NULL);
648}
649