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