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