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