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