panel_frame_view.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
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
492void PanelFrameView::SizeConstraintsChanged() {
493}
494
495gfx::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
503const char* PanelFrameView::GetClassName() const {
504  return kViewClassName;
505}
506
507gfx::Size PanelFrameView::GetMinimumSize() const {
508  return panel_view_->GetMinimumSize();
509}
510
511gfx::Size PanelFrameView::GetMaximumSize() const {
512  return panel_view_->GetMaximumSize();
513}
514
515void 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
557void PanelFrameView::OnPaint(gfx::Canvas* canvas) {
558  UpdateControlStyles(GetPaintState());
559  PaintFrameBackground(canvas);
560  PaintFrameEdge(canvas);
561}
562
563bool 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
579bool 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
598void 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
605void PanelFrameView::OnMouseCaptureLost() {
606  if (panel_view_->OnTitlebarMouseCaptureLost())
607    return;
608  NonClientFrameView::OnMouseCaptureLost();
609}
610
611void 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
625bool 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
633gfx::ImageSkia PanelFrameView::GetFaviconForTabIconView() {
634  return panel_view_->window()->widget_delegate()->GetWindowIcon();
635}
636
637gfx::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
647int PanelFrameView::TitlebarHeight() const {
648  return panel::kTitlebarHeight;
649}
650
651int PanelFrameView::BorderThickness() const {
652  return is_frameless_ ? 0 : kNonAeroBorderThickness;
653}
654
655PanelFrameView::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
666SkColor PanelFrameView::GetTitleColor(PaintState paint_state) const {
667  return kTitleTextDefaultColor;
668}
669
670const 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
687void PanelFrameView::UpdateControlStyles(PaintState paint_state) {
688  title_label_->SetEnabledColor(GetTitleColor(paint_state));
689}
690
691void 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
715void 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
773bool 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