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