panel_frame_view.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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/aura/window.h"
16#include "ui/base/hit_test.h"
17#include "ui/base/l10n/l10n_util.h"
18#include "ui/base/resource/resource_bundle.h"
19#include "ui/gfx/canvas.h"
20#include "ui/gfx/font_list.h"
21#include "ui/gfx/path.h"
22#include "ui/gfx/screen.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
35namespace {
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.
40const int kNonAeroBorderThickness = 1;
41
42// The height and width in pixels of the icon.
43const int kIconSize = 16;
44
45// The extra padding between the button and the top edge.
46const int kExtraPaddingBetweenButtonAndTop = 1;
47
48// Colors used to draw titlebar background under default theme.
49const SkColor kActiveBackgroundDefaultColor = SkColorSetRGB(0x3a, 0x3d, 0x3d);
50const SkColor kInactiveBackgroundDefaultColor = SkColorSetRGB(0x7a, 0x7c, 0x7c);
51const SkColor kAttentionBackgroundDefaultColor =
52    SkColorSetRGB(0x53, 0xa9, 0x3f);
53
54// Color used to draw the minimized panel.
55const SkColor kMinimizeBackgroundDefaultColor = SkColorSetRGB(0xf5, 0xf4, 0xf0);
56
57// Color used to draw the title text under default theme.
58const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9);
59
60gfx::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)
67const 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
79const 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
91const 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
104const 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
117const 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
126const 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
135const 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
144const 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
154const gfx::ImageSkia* GetActiveBackgroundDefaultImage() {
155  static gfx::ImageSkia* image = NULL;
156  if (!image)
157    image = CreateImageForColor(kActiveBackgroundDefaultColor);
158  return image;
159}
160
161const gfx::ImageSkia* GetInactiveBackgroundDefaultImage() {
162  static gfx::ImageSkia* image = NULL;
163  if (!image)
164    image = CreateImageForColor(kInactiveBackgroundDefaultColor);
165  return image;
166}
167
168const gfx::ImageSkia* GetAttentionBackgroundDefaultImage() {
169  static gfx::ImageSkia* image = NULL;
170  if (!image)
171    image = CreateImageForColor(kAttentionBackgroundDefaultColor);
172  return image;
173}
174
175const gfx::ImageSkia* GetMinimizeBackgroundDefaultImage() {
176  static gfx::ImageSkia* image = NULL;
177  if (!image)
178    image = CreateImageForColor(kMinimizeBackgroundDefaultColor);
179  return image;
180}
181
182int 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.
222bool 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
240const char PanelFrameView::kViewClassName[] = "PanelFrameView";
241
242PanelFrameView::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
253PanelFrameView::~PanelFrameView() {
254}
255
256void 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
323void PanelFrameView::UpdateTitle() {
324  UpdateWindowTitle();
325}
326
327void PanelFrameView::UpdateIcon() {
328  UpdateWindowIcon();
329}
330
331void PanelFrameView::UpdateThrobber() {
332  title_icon_->Update();
333}
334
335void 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
346void 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
368gfx::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
397gfx::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
409int 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
440void 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
480void PanelFrameView::ResetWindowControls() {
481  // The controls aren't affected by this constraint.
482}
483
484void PanelFrameView::UpdateWindowIcon() {
485  title_icon_->SchedulePaint();
486}
487
488void PanelFrameView::UpdateWindowTitle() {
489  title_label_->SetText(panel_view_->panel()->GetWindowTitle());
490}
491
492gfx::Size PanelFrameView::GetPreferredSize() const {
493  gfx::Size pref_size =
494      panel_view_->window()->client_view()->GetPreferredSize();
495  gfx::Rect bounds(0, 0, pref_size.width(), pref_size.height());
496  return panel_view_->window()->non_client_view()->
497      GetWindowBoundsForClientBounds(bounds).size();
498}
499
500const char* PanelFrameView::GetClassName() const {
501  return kViewClassName;
502}
503
504gfx::Size PanelFrameView::GetMinimumSize() const {
505  return panel_view_->GetMinimumSize();
506}
507
508gfx::Size PanelFrameView::GetMaximumSize() const {
509  return panel_view_->GetMaximumSize();
510}
511
512void PanelFrameView::Layout() {
513  is_frameless_ = ShouldRenderAsFrameless();
514
515  // Layout the close button.
516  int right = width();
517  close_button_->SetBounds(
518      width() - panel::kTitlebarRightPadding - panel::kPanelButtonSize,
519      (TitlebarHeight() - panel::kPanelButtonSize) / 2 +
520          kExtraPaddingBetweenButtonAndTop,
521      panel::kPanelButtonSize,
522      panel::kPanelButtonSize);
523  right = close_button_->x();
524
525  // Layout the minimize and restore button. Both occupy the same space,
526  // but at most one is visible at any time.
527  minimize_button_->SetBounds(
528      right - panel::kButtonPadding - panel::kPanelButtonSize,
529      (TitlebarHeight() - panel::kPanelButtonSize) / 2 +
530          kExtraPaddingBetweenButtonAndTop,
531      panel::kPanelButtonSize,
532      panel::kPanelButtonSize);
533  restore_button_->SetBoundsRect(minimize_button_->bounds());
534  right = minimize_button_->x();
535
536  // Layout the icon.
537  int icon_y = (TitlebarHeight() - kIconSize) / 2;
538  title_icon_->SetBounds(
539      panel::kTitlebarLeftPadding,
540      icon_y,
541      kIconSize,
542      kIconSize);
543
544  // Layout the title.
545  int title_x = title_icon_->bounds().right() + panel::kIconAndTitlePadding;
546  int title_height = title_label_->font_list().GetHeight();
547  title_label_->SetBounds(
548      title_x,
549      icon_y + ((kIconSize - title_height - 1) / 2),
550      std::max(0, right - panel::kTitleAndButtonPadding - title_x),
551      title_height);
552}
553
554void PanelFrameView::OnPaint(gfx::Canvas* canvas) {
555  UpdateControlStyles(GetPaintState());
556  PaintFrameBackground(canvas);
557  PaintFrameEdge(canvas);
558}
559
560bool PanelFrameView::OnMousePressed(const ui::MouseEvent& event) {
561  // If the mouse location falls within the resizing area of the titlebar, do
562  // not handle the event so that the system resizing logic can kick in.
563  if (event.IsOnlyLeftMouseButton() &&
564      !IsWithinResizingArea(event.location())) {
565    // |event.location| is in the view's coordinate system. Convert it to the
566    // screen coordinate system.
567    gfx::Point mouse_location = event.location();
568    views::View::ConvertPointToScreen(this, &mouse_location);
569
570    if (panel_view_->OnTitlebarMousePressed(mouse_location))
571      return true;
572  }
573  return NonClientFrameView::OnMousePressed(event);
574}
575
576bool PanelFrameView::OnMouseDragged(const ui::MouseEvent& event) {
577#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
578  // Converting the mouse location to screen coordinates returns an incorrect
579  // location while the panel is moving. See crbug.com/353393 for more details.
580  // TODO(pkotwicz): Fix conversion to screen coordinates
581  gfx::Screen* screen = gfx::Screen::GetNativeScreen();
582  gfx::Point mouse_location = screen->GetCursorScreenPoint();
583#else
584  // |event.location| is in the view's coordinate system. Convert it to the
585  // screen coordinate system.
586  gfx::Point mouse_location = event.location();
587  views::View::ConvertPointToScreen(this, &mouse_location);
588#endif
589
590  if (panel_view_->OnTitlebarMouseDragged(mouse_location))
591    return true;
592  return NonClientFrameView::OnMouseDragged(event);
593}
594
595void PanelFrameView::OnMouseReleased(const ui::MouseEvent& event) {
596  if (panel_view_->OnTitlebarMouseReleased(
597          event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER))
598    return;
599  NonClientFrameView::OnMouseReleased(event);
600}
601
602void PanelFrameView::OnMouseCaptureLost() {
603  if (panel_view_->OnTitlebarMouseCaptureLost())
604    return;
605  NonClientFrameView::OnMouseCaptureLost();
606}
607
608void PanelFrameView::ButtonPressed(views::Button* sender,
609                                   const ui::Event& event) {
610  if (sender == close_button_) {
611    panel_view_->ClosePanel();
612  } else {
613    panel::ClickModifier modifier =
614        event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER;
615    if (sender == minimize_button_)
616      panel_view_->panel()->OnMinimizeButtonClicked(modifier);
617    else if (sender == restore_button_)
618      panel_view_->panel()->OnRestoreButtonClicked(modifier);
619  }
620}
621
622bool PanelFrameView::ShouldTabIconViewAnimate() const {
623  // This function is queried during the creation of the window as the
624  // TabIconView we host is initialized, so we need to NULL check the selected
625  // WebContents because in this condition there is not yet a selected tab.
626  content::WebContents* contents = panel_view_->panel()->GetWebContents();
627  return contents ? contents->IsLoading() : false;
628}
629
630gfx::ImageSkia PanelFrameView::GetFaviconForTabIconView() {
631  return panel_view_->window()->widget_delegate()->GetWindowIcon();
632}
633
634gfx::Size PanelFrameView::NonClientAreaSize() const {
635  if (is_frameless_)
636    return gfx::Size(0, TitlebarHeight());
637  // When the frame is present, the width of non-client area consists of
638  // left and right borders, while the height consists of the top area
639  // (titlebar) and the bottom border.
640  return gfx::Size(2 * kNonAeroBorderThickness,
641                   TitlebarHeight() + kNonAeroBorderThickness);
642}
643
644int PanelFrameView::TitlebarHeight() const {
645  return panel::kTitlebarHeight;
646}
647
648int PanelFrameView::BorderThickness() const {
649  return is_frameless_ ? 0 : kNonAeroBorderThickness;
650}
651
652PanelFrameView::PaintState PanelFrameView::GetPaintState() const {
653  if (panel_view_->panel()->IsDrawingAttention())
654    return PAINT_FOR_ATTENTION;
655  if (bounds().height() <= panel::kMinimizedPanelHeight)
656    return PAINT_AS_MINIMIZED;
657  if (panel_view_->IsPanelActive() &&
658           !panel_view_->force_to_paint_as_inactive())
659    return PAINT_AS_ACTIVE;
660  return PAINT_AS_INACTIVE;
661}
662
663SkColor PanelFrameView::GetTitleColor(PaintState paint_state) const {
664  return kTitleTextDefaultColor;
665}
666
667const gfx::ImageSkia* PanelFrameView::GetFrameBackground(
668    PaintState paint_state) const {
669  switch (paint_state) {
670    case PAINT_AS_INACTIVE:
671      return GetInactiveBackgroundDefaultImage();
672    case PAINT_AS_ACTIVE:
673      return GetActiveBackgroundDefaultImage();
674    case PAINT_AS_MINIMIZED:
675      return GetMinimizeBackgroundDefaultImage();
676    case PAINT_FOR_ATTENTION:
677      return GetAttentionBackgroundDefaultImage();
678    default:
679      NOTREACHED();
680      return GetInactiveBackgroundDefaultImage();
681  }
682}
683
684void PanelFrameView::UpdateControlStyles(PaintState paint_state) {
685  title_label_->SetEnabledColor(GetTitleColor(paint_state));
686}
687
688void PanelFrameView::PaintFrameBackground(gfx::Canvas* canvas) {
689  // We only need to paint the title-bar since no resizing border is shown.
690  // Instead, we allow part of the inner content area be used to trigger the
691  // mouse resizing.
692  int titlebar_height = TitlebarHeight();
693  const gfx::ImageSkia* image = GetFrameBackground(GetPaintState());
694  canvas->TileImageInt(*image, 0, 0, width(), titlebar_height);
695
696  if (is_frameless_)
697    return;
698
699  // Left border, below title-bar.
700  canvas->TileImageInt(*image, 0, titlebar_height, kNonAeroBorderThickness,
701      height() - titlebar_height);
702
703  // Right border, below title-bar.
704  canvas->TileImageInt(*image, width() - kNonAeroBorderThickness,
705      titlebar_height, kNonAeroBorderThickness, height() - titlebar_height);
706
707  // Bottom border.
708  canvas->TileImageInt(*image, 0, height() - kNonAeroBorderThickness, width(),
709      kNonAeroBorderThickness);
710}
711
712void PanelFrameView::PaintFrameEdge(gfx::Canvas* canvas) {
713#if defined(OS_WIN)
714  // Border is not needed when panel is not shown as minimized.
715  if (GetPaintState() != PAINT_AS_MINIMIZED)
716    return;
717
718  const gfx::ImageSkia& top_left_image = GetTopLeftCornerImage(corner_style_);
719  const gfx::ImageSkia& top_right_image = GetTopRightCornerImage(corner_style_);
720  const gfx::ImageSkia& bottom_left_image =
721      GetBottomLeftCornerImage(corner_style_);
722  const gfx::ImageSkia& bottom_right_image =
723      GetBottomRightCornerImage(corner_style_);
724  const gfx::ImageSkia& top_image = GetTopEdgeImage();
725  const gfx::ImageSkia& bottom_image = GetBottomEdgeImage();
726  const gfx::ImageSkia& left_image = GetLeftEdgeImage();
727  const gfx::ImageSkia& right_image = GetRightEdgeImage();
728
729  // Draw the top border.
730  canvas->DrawImageInt(top_left_image, 0, 0);
731  canvas->TileImageInt(top_image,
732                       top_left_image.width(),
733                       0,
734                       width() - top_right_image.width(),
735                       top_image.height());
736  canvas->DrawImageInt(top_right_image, width() - top_right_image.width(), 0);
737
738  // Draw the right border.
739  canvas->TileImageInt(right_image,
740                       width() - right_image.width(),
741                       top_right_image.height(),
742                       right_image.width(),
743                       height() - top_right_image.height() -
744                           bottom_right_image.height());
745
746  // Draw the bottom border.
747  canvas->DrawImageInt(bottom_right_image,
748                       width() - bottom_right_image.width(),
749                       height() - bottom_right_image.height());
750  canvas->TileImageInt(bottom_image,
751                       bottom_left_image.width(),
752                       height() - bottom_image.height(),
753                       width() - bottom_left_image.width() -
754                           bottom_right_image.width(),
755                       bottom_image.height());
756  canvas->DrawImageInt(bottom_left_image,
757                       0,
758                       height() - bottom_left_image.height());
759
760  // Draw the left border.
761  canvas->TileImageInt(left_image,
762                       0,
763                       top_left_image.height(),
764                       left_image.width(),
765                       height() - top_left_image.height() -
766                           bottom_left_image.height());
767#endif
768}
769
770bool PanelFrameView::IsWithinResizingArea(
771    const gfx::Point& mouse_location) const {
772  panel::Resizability resizability = panel_view_->panel()->CanResizeByMouse();
773  int edge_hittest = GetFrameEdgeHitTest(
774      mouse_location, size(), PanelView::kResizeInsideBoundsSize, resizability);
775  return edge_hittest != HTNOWHERE;
776}
777