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