1 // Copyright (c) 2012 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/panels/panel_frame_view.h" 6 7 #include "chrome/browser/ui/panels/panel.h" 8 #include "chrome/browser/ui/panels/panel_constants.h" 9 #include "chrome/browser/ui/views/panels/panel_view.h" 10 #include "chrome/browser/ui/views/tab_icon_view.h" 11 #include "content/public/browser/web_contents.h" 12 #include "grit/generated_resources.h" 13 #include "grit/theme_resources.h" 14 #include "grit/ui_resources.h" 15 #include "ui/base/hit_test.h" 16 #include "ui/base/l10n/l10n_util.h" 17 #include "ui/base/resource/resource_bundle.h" 18 #include "ui/gfx/canvas.h" 19 #include "ui/gfx/path.h" 20 #include "ui/views/controls/button/image_button.h" 21 #include "ui/views/controls/label.h" 22 #include "ui/views/widget/widget.h" 23 #include "ui/views/widget/widget_delegate.h" 24 25 #if defined(OS_WIN) 26 #include "base/win/scoped_gdi_object.h" 27 #include "ui/base/win/shell.h" 28 #include "ui/gfx/path_win.h" 29 #include "ui/views/win/hwnd_util.h" 30 #endif 31 32 #if defined(USE_AURA) 33 #include "ui/aura/window.h" 34 #endif 35 36 namespace { 37 38 // The thickness of the border when Aero is not enabled. In this case, the 39 // shadow around the window will not be painted by the system and we need to 40 // paint a frame in order to differentiate the client area from the background. 41 const int kNonAeroBorderThickness = 1; 42 43 // The height and width in pixels of the icon. 44 const int kIconSize = 16; 45 46 // The font to use to draw the title. 47 const char* kTitleFontName = "Arial Bold"; 48 const int kTitleFontSize = 14; 49 50 // The extra padding between the button and the top edge. 51 const int kExtraPaddingBetweenButtonAndTop = 1; 52 53 // Colors used to draw titlebar background under default theme. 54 const SkColor kActiveBackgroundDefaultColor = SkColorSetRGB(0x3a, 0x3d, 0x3d); 55 const SkColor kInactiveBackgroundDefaultColor = SkColorSetRGB(0x7a, 0x7c, 0x7c); 56 const SkColor kAttentionBackgroundDefaultColor = 57 SkColorSetRGB(0x53, 0xa9, 0x3f); 58 59 // Color used to draw the minimized panel. 60 const SkColor kMinimizeBackgroundDefaultColor = SkColorSetRGB(0xf5, 0xf4, 0xf0); 61 const SkColor kMinimizeBorderDefaultColor = SkColorSetRGB(0xc9, 0xc9, 0xc9); 62 63 // Color used to draw the title text under default theme. 64 const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9); 65 66 gfx::ImageSkia* CreateImageForColor(SkColor color) { 67 gfx::Canvas canvas(gfx::Size(1, 1), ui::SCALE_FACTOR_100P, true); 68 canvas.DrawColor(color); 69 return new gfx::ImageSkia(canvas.ExtractImageRep()); 70 } 71 72 const gfx::ImageSkia& GetTopLeftCornerImage(panel::CornerStyle corner_style) { 73 static gfx::ImageSkia* rounded_image = NULL; 74 static gfx::ImageSkia* non_rounded_image = NULL; 75 if (!rounded_image) { 76 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 77 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_LEFT_CORNER); 78 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_TOP_LEFT_CORNER); 79 } 80 return (corner_style & panel::TOP_ROUNDED) ? *rounded_image 81 : *non_rounded_image; 82 } 83 84 const gfx::ImageSkia& GetTopRightCornerImage(panel::CornerStyle corner_style) { 85 static gfx::ImageSkia* rounded_image = NULL; 86 static gfx::ImageSkia* non_rounded_image = NULL; 87 if (!rounded_image) { 88 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 89 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_RIGHT_CORNER); 90 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_TOP_RIGHT_CORNER); 91 } 92 return (corner_style & panel::TOP_ROUNDED) ? *rounded_image 93 : *non_rounded_image; 94 } 95 96 const gfx::ImageSkia& GetBottomLeftCornerImage( 97 panel::CornerStyle corner_style) { 98 static gfx::ImageSkia* rounded_image = NULL; 99 static gfx::ImageSkia* non_rounded_image = NULL; 100 if (!rounded_image) { 101 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 102 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER); 103 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_BOTTOM_LEFT_CORNER); 104 } 105 return (corner_style & panel::BOTTOM_ROUNDED) ? *rounded_image 106 : *non_rounded_image; 107 } 108 109 const gfx::ImageSkia& GetBottomRightCornerImage( 110 panel::CornerStyle corner_style) { 111 static gfx::ImageSkia* rounded_image = NULL; 112 static gfx::ImageSkia* non_rounded_image = NULL; 113 if (!rounded_image) { 114 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 115 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER); 116 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_BOTTOM_RIGHT_CORNER); 117 } 118 return (corner_style & panel::BOTTOM_ROUNDED) ? *rounded_image 119 : *non_rounded_image; 120 } 121 122 const gfx::ImageSkia& GetTopEdgeImage() { 123 static gfx::ImageSkia* image = NULL; 124 if (!image) { 125 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 126 image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_CENTER); 127 } 128 return *image; 129 } 130 131 const gfx::ImageSkia& GetBottomEdgeImage() { 132 static gfx::ImageSkia* image = NULL; 133 if (!image) { 134 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 135 image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_CENTER); 136 } 137 return *image; 138 } 139 140 const gfx::ImageSkia& GetLeftEdgeImage() { 141 static gfx::ImageSkia* image = NULL; 142 if (!image) { 143 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 144 image = rb.GetImageSkiaNamed(IDR_WINDOW_LEFT_SIDE); 145 } 146 return *image; 147 } 148 149 const gfx::ImageSkia& GetRightEdgeImage() { 150 static gfx::ImageSkia* image = NULL; 151 if (!image) { 152 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 153 image = rb.GetImageSkiaNamed(IDR_WINDOW_RIGHT_SIDE); 154 } 155 return *image; 156 } 157 158 const gfx::Font& GetTitleFont() { 159 static gfx::Font* font = NULL; 160 if (!font) 161 font = new gfx::Font(kTitleFontName, kTitleFontSize); 162 return *font; 163 } 164 165 const gfx::ImageSkia* GetActiveBackgroundDefaultImage() { 166 static gfx::ImageSkia* image = NULL; 167 if (!image) 168 image = CreateImageForColor(kActiveBackgroundDefaultColor); 169 return image; 170 } 171 172 const gfx::ImageSkia* GetInactiveBackgroundDefaultImage() { 173 static gfx::ImageSkia* image = NULL; 174 if (!image) 175 image = CreateImageForColor(kInactiveBackgroundDefaultColor); 176 return image; 177 } 178 179 const gfx::ImageSkia* GetAttentionBackgroundDefaultImage() { 180 static gfx::ImageSkia* image = NULL; 181 if (!image) 182 image = CreateImageForColor(kAttentionBackgroundDefaultColor); 183 return image; 184 } 185 186 const gfx::ImageSkia* GetMinimizeBackgroundDefaultImage() { 187 static gfx::ImageSkia* image = NULL; 188 if (!image) 189 image = CreateImageForColor(kMinimizeBackgroundDefaultColor); 190 return image; 191 } 192 193 int GetFrameEdgeHitTest(const gfx::Point& point, 194 const gfx::Size& frame_size, 195 int resize_area_size, 196 panel::Resizability resizability) { 197 int x = point.x(); 198 int y = point.y(); 199 int width = frame_size.width(); 200 int height = frame_size.height(); 201 if (x < resize_area_size) { 202 if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP_LEFT)) { 203 return HTTOPLEFT; 204 } else if (y >= height - resize_area_size && 205 (resizability & panel::RESIZABLE_BOTTOM_LEFT)) { 206 return HTBOTTOMLEFT; 207 } else if (resizability & panel::RESIZABLE_LEFT) { 208 return HTLEFT; 209 } 210 } else if (x >= width - resize_area_size) { 211 if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP_RIGHT)) { 212 return HTTOPRIGHT; 213 } else if (y >= height - resize_area_size && 214 (resizability & panel::RESIZABLE_BOTTOM_RIGHT)) { 215 return HTBOTTOMRIGHT; 216 } else if (resizability & panel::RESIZABLE_RIGHT) { 217 return HTRIGHT; 218 } 219 } 220 221 if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP)) { 222 return HTTOP; 223 } else if (y >= height - resize_area_size && 224 (resizability & panel::RESIZABLE_BOTTOM)) { 225 return HTBOTTOM; 226 } 227 228 return HTNOWHERE; 229 } 230 231 // Frameless is only supported when Aero is enabled and shadow effect is 232 // present. 233 bool ShouldRenderAsFrameless() { 234 #if defined(OS_WIN) 235 bool is_frameless = ui::win::IsAeroGlassEnabled(); 236 if (is_frameless) { 237 BOOL shadow_enabled = FALSE; 238 if (::SystemParametersInfo(SPI_GETDROPSHADOW, 0, &shadow_enabled, 0) && 239 !shadow_enabled) 240 is_frameless = false; 241 } 242 return is_frameless; 243 #else 244 return false; 245 #endif 246 } 247 248 } // namespace 249 250 // static 251 const char PanelFrameView::kViewClassName[] = "PanelFrameView"; 252 253 PanelFrameView::PanelFrameView(PanelView* panel_view) 254 : is_frameless_(ShouldRenderAsFrameless()), 255 panel_view_(panel_view), 256 close_button_(NULL), 257 minimize_button_(NULL), 258 restore_button_(NULL), 259 title_icon_(NULL), 260 title_label_(NULL), 261 corner_style_(panel::ALL_ROUNDED) { 262 } 263 264 PanelFrameView::~PanelFrameView() { 265 } 266 267 void PanelFrameView::Init() { 268 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 269 270 close_button_ = new views::ImageButton(this); 271 close_button_->SetImage(views::CustomButton::STATE_NORMAL, 272 rb.GetImageSkiaNamed(IDR_PANEL_CLOSE)); 273 close_button_->SetImage(views::CustomButton::STATE_HOVERED, 274 rb.GetImageSkiaNamed(IDR_PANEL_CLOSE_H)); 275 close_button_->SetImage(views::CustomButton::STATE_PRESSED, 276 rb.GetImageSkiaNamed(IDR_PANEL_CLOSE_C)); 277 close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, 278 views::ImageButton::ALIGN_MIDDLE); 279 string16 tooltip_text = l10n_util::GetStringUTF16(IDS_PANEL_CLOSE_TOOLTIP); 280 close_button_->SetTooltipText(tooltip_text); 281 AddChildView(close_button_); 282 283 minimize_button_ = new views::ImageButton(this); 284 minimize_button_->SetImage(views::CustomButton::STATE_NORMAL, 285 rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE)); 286 minimize_button_->SetImage(views::CustomButton::STATE_HOVERED, 287 rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE_H)); 288 minimize_button_->SetImage(views::CustomButton::STATE_PRESSED, 289 rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE_C)); 290 tooltip_text = l10n_util::GetStringUTF16(IDS_PANEL_MINIMIZE_TOOLTIP); 291 minimize_button_->SetTooltipText(tooltip_text); 292 minimize_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, 293 views::ImageButton::ALIGN_MIDDLE); 294 AddChildView(minimize_button_); 295 296 restore_button_ = new views::ImageButton(this); 297 restore_button_->SetImage(views::CustomButton::STATE_NORMAL, 298 rb.GetImageSkiaNamed(IDR_PANEL_RESTORE)); 299 restore_button_->SetImage(views::CustomButton::STATE_HOVERED, 300 rb.GetImageSkiaNamed(IDR_PANEL_RESTORE_H)); 301 restore_button_->SetImage(views::CustomButton::STATE_PRESSED, 302 rb.GetImageSkiaNamed(IDR_PANEL_RESTORE_C)); 303 restore_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, 304 views::ImageButton::ALIGN_MIDDLE); 305 tooltip_text = l10n_util::GetStringUTF16(IDS_PANEL_RESTORE_TOOLTIP); 306 restore_button_->SetTooltipText(tooltip_text); 307 restore_button_->SetVisible(false); // only visible when panel is minimized 308 AddChildView(restore_button_); 309 310 title_icon_ = new TabIconView(this); 311 title_icon_->set_is_light(true); 312 AddChildView(title_icon_); 313 title_icon_->Update(); 314 315 title_label_ = new views::Label(panel_view_->panel()->GetWindowTitle()); 316 title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 317 title_label_->SetAutoColorReadabilityEnabled(false); 318 title_label_->SetFont(GetTitleFont()); 319 AddChildView(title_label_); 320 321 #if defined(USE_AURA) 322 // Compute the thickness of the client area that needs to be counted towards 323 // mouse resizing. 324 int thickness_for_mouse_resizing = 325 PanelView::kResizeInsideBoundsSize - BorderThickness(); 326 aura::Window* window = panel_view_->GetNativePanelWindow(); 327 window->set_hit_test_bounds_override_inner( 328 gfx::Insets(thickness_for_mouse_resizing, thickness_for_mouse_resizing, 329 thickness_for_mouse_resizing, thickness_for_mouse_resizing)); 330 #endif 331 } 332 333 void PanelFrameView::UpdateTitle() { 334 UpdateWindowTitle(); 335 } 336 337 void PanelFrameView::UpdateIcon() { 338 UpdateWindowIcon(); 339 } 340 341 void PanelFrameView::UpdateThrobber() { 342 title_icon_->Update(); 343 } 344 345 void PanelFrameView::UpdateTitlebarMinimizeRestoreButtonVisibility() { 346 Panel* panel = panel_view_->panel(); 347 minimize_button_->SetVisible(panel->CanShowMinimizeButton()); 348 restore_button_->SetVisible(panel->CanShowRestoreButton()); 349 350 // Reset the button states in case that the hover states are not cleared when 351 // mouse is clicked but not moved. 352 minimize_button_->SetState(views::CustomButton::STATE_NORMAL); 353 restore_button_->SetState(views::CustomButton::STATE_NORMAL); 354 } 355 356 void PanelFrameView::SetWindowCornerStyle(panel::CornerStyle corner_style) { 357 corner_style_ = corner_style; 358 359 #if defined(OS_WIN) 360 // Changing the window region is going to force a paint. Only change the 361 // window region if the region really differs. 362 HWND native_window = views::HWNDForWidget(panel_view_->window()); 363 base::win::ScopedRegion current_region(::CreateRectRgn(0, 0, 0, 0)); 364 int current_region_result = ::GetWindowRgn(native_window, current_region); 365 366 gfx::Path window_mask; 367 GetWindowMask(size(), &window_mask); 368 base::win::ScopedRegion new_region(gfx::CreateHRGNFromSkPath(window_mask)); 369 370 if (current_region_result == ERROR || 371 !::EqualRgn(current_region, new_region)) { 372 // SetWindowRgn takes ownership of the new_region. 373 ::SetWindowRgn(native_window, new_region.release(), TRUE); 374 } 375 #endif 376 } 377 378 gfx::Rect PanelFrameView::GetBoundsForClientView() const { 379 // The origin of client-area bounds starts after left border and titlebar and 380 // spans until hitting the right and bottom borders. 381 // +------------------------------+ 382 // | Top Titlebar | 383 // |-+--------------------------+-| 384 // |L| |R| 385 // |e| |i| 386 // |f| |g| 387 // |t| |h| 388 // | | Client |t| 389 // | | | | 390 // |B| Area |B| 391 // |o| |o| 392 // |r| |r| 393 // |d| |d| 394 // |e| |e| 395 // |r| |r| 396 // | +--------------------------+ | 397 // | Bottom Border | 398 // +------------------------------+ 399 int titlebar_height = TitlebarHeight(); 400 int border_thickness = BorderThickness(); 401 return gfx::Rect(border_thickness, 402 titlebar_height, 403 std::max(0, width() - border_thickness * 2), 404 std::max(0, height() - titlebar_height - border_thickness)); 405 } 406 407 gfx::Rect PanelFrameView::GetWindowBoundsForClientBounds( 408 const gfx::Rect& client_bounds) const { 409 int titlebar_height = TitlebarHeight(); 410 int border_thickness = BorderThickness(); 411 // The window bounds include both client area and non-client area (titlebar 412 // and left, right and bottom borders). 413 return gfx::Rect(client_bounds.x() - border_thickness, 414 client_bounds.y() - titlebar_height, 415 client_bounds.width() + border_thickness * 2, 416 client_bounds.height() + titlebar_height + border_thickness); 417 } 418 419 int PanelFrameView::NonClientHitTest(const gfx::Point& point) { 420 panel::Resizability resizability = panel_view_->panel()->CanResizeByMouse(); 421 422 // Check the frame first, as we allow a small area overlapping the contents 423 // to be used for resize handles. 424 int frame_component = GetFrameEdgeHitTest( 425 point, size(), PanelView::kResizeInsideBoundsSize, resizability); 426 427 if (frame_component != HTNOWHERE) 428 return frame_component; 429 430 int client_component = 431 panel_view_->window()->client_view()->NonClientHitTest(point); 432 if (client_component != HTNOWHERE) 433 return client_component; 434 435 if (close_button_ && close_button_->visible() && 436 close_button_->GetMirroredBounds().Contains(point)) 437 return HTCLOSE; 438 439 if (minimize_button_ && minimize_button_->visible() && 440 minimize_button_->GetMirroredBounds().Contains(point)) 441 return HTMINBUTTON; 442 443 if (restore_button_ && restore_button_->visible() && 444 restore_button_->GetMirroredBounds().Contains(point)) 445 return HTMAXBUTTON; 446 447 return HTNOWHERE; 448 } 449 450 void PanelFrameView::GetWindowMask(const gfx::Size& size, 451 gfx::Path* window_mask) { 452 int width = size.width(); 453 int height = size.height(); 454 455 if (corner_style_ & panel::TOP_ROUNDED) { 456 window_mask->moveTo(0, 3); 457 window_mask->lineTo(1, 2); 458 window_mask->lineTo(1, 1); 459 window_mask->lineTo(2, 1); 460 window_mask->lineTo(3, 0); 461 window_mask->lineTo(SkIntToScalar(width - 3), 0); 462 window_mask->lineTo(SkIntToScalar(width - 2), 1); 463 window_mask->lineTo(SkIntToScalar(width - 1), 1); 464 window_mask->lineTo(SkIntToScalar(width - 1), 2); 465 window_mask->lineTo(SkIntToScalar(width - 1), 3); 466 } else { 467 window_mask->moveTo(0, 0); 468 window_mask->lineTo(width, 0); 469 } 470 471 if (corner_style_ & panel::BOTTOM_ROUNDED) { 472 window_mask->lineTo(SkIntToScalar(width - 1), SkIntToScalar(height - 4)); 473 window_mask->lineTo(SkIntToScalar(width - 2), SkIntToScalar(height - 3)); 474 window_mask->lineTo(SkIntToScalar(width - 2), SkIntToScalar(height - 2)); 475 window_mask->lineTo(SkIntToScalar(width - 3), SkIntToScalar(height - 2)); 476 window_mask->lineTo(SkIntToScalar(width - 4), SkIntToScalar(height - 1)); 477 window_mask->lineTo(3, SkIntToScalar(height - 1)); 478 window_mask->lineTo(2, SkIntToScalar(height - 2)); 479 window_mask->lineTo(1, SkIntToScalar(height - 2)); 480 window_mask->lineTo(1, SkIntToScalar(height - 3)); 481 window_mask->lineTo(0, SkIntToScalar(height - 4)); 482 } else { 483 window_mask->lineTo(SkIntToScalar(width), SkIntToScalar(height)); 484 window_mask->lineTo(0, SkIntToScalar(height)); 485 } 486 487 window_mask->close(); 488 } 489 490 void PanelFrameView::ResetWindowControls() { 491 // The controls aren't affected by this constraint. 492 } 493 494 void PanelFrameView::UpdateWindowIcon() { 495 title_icon_->SchedulePaint(); 496 } 497 498 void PanelFrameView::UpdateWindowTitle() { 499 title_label_->SetText(panel_view_->panel()->GetWindowTitle()); 500 } 501 502 gfx::Size PanelFrameView::GetPreferredSize() { 503 gfx::Size pref_size = 504 panel_view_->window()->client_view()->GetPreferredSize(); 505 gfx::Rect bounds(0, 0, pref_size.width(), pref_size.height()); 506 return panel_view_->window()->non_client_view()-> 507 GetWindowBoundsForClientBounds(bounds).size(); 508 } 509 510 const char* PanelFrameView::GetClassName() const { 511 return kViewClassName; 512 } 513 514 gfx::Size PanelFrameView::GetMinimumSize() { 515 return panel_view_->GetMinimumSize(); 516 } 517 518 gfx::Size PanelFrameView::GetMaximumSize() { 519 return panel_view_->GetMaximumSize(); 520 } 521 522 void PanelFrameView::Layout() { 523 is_frameless_ = ShouldRenderAsFrameless(); 524 525 // Layout the close button. 526 int right = width(); 527 close_button_->SetBounds( 528 width() - panel::kTitlebarRightPadding - panel::kPanelButtonSize, 529 (TitlebarHeight() - panel::kPanelButtonSize) / 2 + 530 kExtraPaddingBetweenButtonAndTop, 531 panel::kPanelButtonSize, 532 panel::kPanelButtonSize); 533 right = close_button_->x(); 534 535 // Layout the minimize and restore button. Both occupy the same space, 536 // but at most one is visible at any time. 537 minimize_button_->SetBounds( 538 right - panel::kButtonPadding - panel::kPanelButtonSize, 539 (TitlebarHeight() - panel::kPanelButtonSize) / 2 + 540 kExtraPaddingBetweenButtonAndTop, 541 panel::kPanelButtonSize, 542 panel::kPanelButtonSize); 543 restore_button_->SetBoundsRect(minimize_button_->bounds()); 544 right = minimize_button_->x(); 545 546 // Layout the icon. 547 int icon_y = (TitlebarHeight() - kIconSize) / 2; 548 title_icon_->SetBounds( 549 panel::kTitlebarLeftPadding, 550 icon_y, 551 kIconSize, 552 kIconSize); 553 554 // Layout the title. 555 int title_x = title_icon_->bounds().right() + panel::kIconAndTitlePadding; 556 int title_height = GetTitleFont().GetHeight(); 557 title_label_->SetBounds( 558 title_x, 559 icon_y + ((kIconSize - title_height - 1) / 2), 560 std::max(0, right - panel::kTitleAndButtonPadding - title_x), 561 title_height); 562 } 563 564 void PanelFrameView::OnPaint(gfx::Canvas* canvas) { 565 UpdateControlStyles(GetPaintState()); 566 PaintFrameBackground(canvas); 567 PaintFrameEdge(canvas); 568 } 569 570 bool PanelFrameView::OnMousePressed(const ui::MouseEvent& event) { 571 if (event.IsOnlyLeftMouseButton()) { 572 // |event.location| is in the view's coordinate system. Convert it to the 573 // screen coordinate system. 574 gfx::Point mouse_location = event.location(); 575 views::View::ConvertPointToScreen(this, &mouse_location); 576 577 // If the mouse location falls within the resizing area of the titlebar, 578 // do not handle the event so that the system resizing logic could kick in. 579 if (!panel_view_->IsWithinResizingArea(mouse_location) && 580 panel_view_->OnTitlebarMousePressed(mouse_location)) 581 return true; 582 } 583 return NonClientFrameView::OnMousePressed(event); 584 } 585 586 bool PanelFrameView::OnMouseDragged(const ui::MouseEvent& event) { 587 // |event.location| is in the view's coordinate system. Convert it to the 588 // screen coordinate system. 589 gfx::Point mouse_location = event.location(); 590 views::View::ConvertPointToScreen(this, &mouse_location); 591 592 if (panel_view_->OnTitlebarMouseDragged(mouse_location)) 593 return true; 594 return NonClientFrameView::OnMouseDragged(event); 595 } 596 597 void PanelFrameView::OnMouseReleased(const ui::MouseEvent& event) { 598 if (panel_view_->OnTitlebarMouseReleased( 599 event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER)) 600 return; 601 NonClientFrameView::OnMouseReleased(event); 602 } 603 604 void PanelFrameView::OnMouseCaptureLost() { 605 if (panel_view_->OnTitlebarMouseCaptureLost()) 606 return; 607 NonClientFrameView::OnMouseCaptureLost(); 608 } 609 610 void PanelFrameView::ButtonPressed(views::Button* sender, 611 const ui::Event& event) { 612 if (sender == close_button_) { 613 panel_view_->ClosePanel(); 614 } else { 615 panel::ClickModifier modifier = 616 event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER; 617 if (sender == minimize_button_) 618 panel_view_->panel()->OnMinimizeButtonClicked(modifier); 619 else if (sender == restore_button_) 620 panel_view_->panel()->OnRestoreButtonClicked(modifier); 621 } 622 } 623 624 bool PanelFrameView::ShouldTabIconViewAnimate() const { 625 // This function is queried during the creation of the window as the 626 // TabIconView we host is initialized, so we need to NULL check the selected 627 // WebContents because in this condition there is not yet a selected tab. 628 content::WebContents* contents = panel_view_->panel()->GetWebContents(); 629 return contents ? contents->IsLoading() : false; 630 } 631 632 gfx::ImageSkia PanelFrameView::GetFaviconForTabIconView() { 633 return panel_view_->window()->widget_delegate()->GetWindowIcon(); 634 } 635 636 gfx::Size PanelFrameView::NonClientAreaSize() const { 637 if (is_frameless_) 638 return gfx::Size(0, TitlebarHeight()); 639 // When the frame is present, the width of non-client area consists of 640 // left and right borders, while the height consists of the top area 641 // (titlebar) and the bottom border. 642 return gfx::Size(2 * kNonAeroBorderThickness, 643 TitlebarHeight() + kNonAeroBorderThickness); 644 } 645 646 int PanelFrameView::TitlebarHeight() const { 647 return panel::kTitlebarHeight; 648 } 649 650 int PanelFrameView::BorderThickness() const { 651 return is_frameless_ ? 0 : kNonAeroBorderThickness; 652 } 653 654 PanelFrameView::PaintState PanelFrameView::GetPaintState() const { 655 if (panel_view_->panel()->IsDrawingAttention()) 656 return PAINT_FOR_ATTENTION; 657 if (bounds().height() <= panel::kMinimizedPanelHeight) 658 return PAINT_AS_MINIMIZED; 659 if (panel_view_->IsPanelActive() && 660 !panel_view_->force_to_paint_as_inactive()) 661 return PAINT_AS_ACTIVE; 662 return PAINT_AS_INACTIVE; 663 } 664 665 SkColor PanelFrameView::GetTitleColor(PaintState paint_state) const { 666 return kTitleTextDefaultColor; 667 } 668 669 const gfx::ImageSkia* PanelFrameView::GetFrameBackground( 670 PaintState paint_state) const { 671 switch (paint_state) { 672 case PAINT_AS_INACTIVE: 673 return GetInactiveBackgroundDefaultImage(); 674 case PAINT_AS_ACTIVE: 675 return GetActiveBackgroundDefaultImage(); 676 case PAINT_AS_MINIMIZED: 677 return GetMinimizeBackgroundDefaultImage(); 678 case PAINT_FOR_ATTENTION: 679 return GetAttentionBackgroundDefaultImage(); 680 default: 681 NOTREACHED(); 682 return GetInactiveBackgroundDefaultImage(); 683 } 684 } 685 686 void PanelFrameView::UpdateControlStyles(PaintState paint_state) { 687 title_label_->SetEnabledColor(GetTitleColor(paint_state)); 688 } 689 690 void PanelFrameView::PaintFrameBackground(gfx::Canvas* canvas) { 691 // We only need to paint the title-bar since no resizing border is shown. 692 // Instead, we allow part of the inner content area be used to trigger the 693 // mouse resizing. 694 int titlebar_height = TitlebarHeight(); 695 const gfx::ImageSkia* image = GetFrameBackground(GetPaintState()); 696 canvas->TileImageInt(*image, 0, 0, width(), titlebar_height); 697 698 if (is_frameless_) 699 return; 700 701 // Left border, below title-bar. 702 canvas->TileImageInt(*image, 0, titlebar_height, kNonAeroBorderThickness, 703 height() - titlebar_height); 704 705 // Right border, below title-bar. 706 canvas->TileImageInt(*image, width() - kNonAeroBorderThickness, 707 titlebar_height, kNonAeroBorderThickness, height() - titlebar_height); 708 709 // Bottom border. 710 canvas->TileImageInt(*image, 0, height() - kNonAeroBorderThickness, width(), 711 kNonAeroBorderThickness); 712 } 713 714 void PanelFrameView::PaintFrameEdge(gfx::Canvas* canvas) { 715 #if defined(OS_WIN) 716 // Border is not needed when panel is not shown as minimized. 717 if (GetPaintState() != PAINT_AS_MINIMIZED) 718 return; 719 720 const gfx::ImageSkia& top_left_image = GetTopLeftCornerImage(corner_style_); 721 const gfx::ImageSkia& top_right_image = GetTopRightCornerImage(corner_style_); 722 const gfx::ImageSkia& bottom_left_image = 723 GetBottomLeftCornerImage(corner_style_); 724 const gfx::ImageSkia& bottom_right_image = 725 GetBottomRightCornerImage(corner_style_); 726 const gfx::ImageSkia& top_image = GetTopEdgeImage(); 727 const gfx::ImageSkia& bottom_image = GetBottomEdgeImage(); 728 const gfx::ImageSkia& left_image = GetLeftEdgeImage(); 729 const gfx::ImageSkia& right_image = GetRightEdgeImage(); 730 731 // Draw the top border. 732 canvas->DrawImageInt(top_left_image, 0, 0); 733 canvas->TileImageInt(top_image, 734 top_left_image.width(), 735 0, 736 width() - top_right_image.width(), 737 top_image.height()); 738 canvas->DrawImageInt(top_right_image, width() - top_right_image.width(), 0); 739 740 // Draw the right border. 741 canvas->TileImageInt(right_image, 742 width() - right_image.width(), 743 top_right_image.height(), 744 right_image.width(), 745 height() - top_right_image.height() - 746 bottom_right_image.height()); 747 748 // Draw the bottom border. 749 canvas->DrawImageInt(bottom_right_image, 750 width() - bottom_right_image.width(), 751 height() - bottom_right_image.height()); 752 canvas->TileImageInt(bottom_image, 753 bottom_left_image.width(), 754 height() - bottom_image.height(), 755 width() - bottom_left_image.width() - 756 bottom_right_image.width(), 757 bottom_image.height()); 758 canvas->DrawImageInt(bottom_left_image, 759 0, 760 height() - bottom_left_image.height()); 761 762 // Draw the left border. 763 canvas->TileImageInt(left_image, 764 0, 765 top_left_image.height(), 766 left_image.width(), 767 height() - top_left_image.height() - 768 bottom_left_image.height()); 769 #endif 770 } 771