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