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