OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h" | 5 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 #include "components/signin/core/common/profile_management_switches.h" | 28 #include "components/signin/core/common/profile_management_switches.h" |
29 #include "content/public/browser/notification_service.h" | 29 #include "content/public/browser/notification_service.h" |
30 #include "content/public/browser/web_contents.h" | 30 #include "content/public/browser/web_contents.h" |
31 #include "grit/components_strings.h" | 31 #include "grit/components_strings.h" |
32 #include "grit/theme_resources.h" | 32 #include "grit/theme_resources.h" |
33 #include "ui/accessibility/ax_view_state.h" | 33 #include "ui/accessibility/ax_view_state.h" |
34 #include "ui/base/hit_test.h" | 34 #include "ui/base/hit_test.h" |
35 #include "ui/base/l10n/l10n_util.h" | 35 #include "ui/base/l10n/l10n_util.h" |
36 #include "ui/base/material_design/material_design_controller.h" | 36 #include "ui/base/material_design/material_design_controller.h" |
37 #include "ui/base/theme_provider.h" | 37 #include "ui/base/theme_provider.h" |
| 38 #include "ui/gfx/animation/throb_animation.h" |
38 #include "ui/gfx/canvas.h" | 39 #include "ui/gfx/canvas.h" |
| 40 #include "ui/gfx/color_utils.h" |
39 #include "ui/gfx/font_list.h" | 41 #include "ui/gfx/font_list.h" |
40 #include "ui/gfx/geometry/rect_conversions.h" | 42 #include "ui/gfx/geometry/rect_conversions.h" |
41 #include "ui/gfx/image/image.h" | 43 #include "ui/gfx/image/image.h" |
42 #include "ui/gfx/image/image_skia.h" | 44 #include "ui/gfx/image/image_skia.h" |
43 #include "ui/gfx/path.h" | 45 #include "ui/gfx/path.h" |
44 #include "ui/gfx/scoped_canvas.h" | 46 #include "ui/gfx/scoped_canvas.h" |
45 #include "ui/resources/grit/ui_resources.h" | 47 #include "ui/resources/grit/ui_resources.h" |
46 #include "ui/views/controls/button/image_button.h" | 48 #include "ui/views/controls/button/image_button.h" |
47 #include "ui/views/controls/image_view.h" | 49 #include "ui/views/controls/image_view.h" |
48 #include "ui/views/controls/label.h" | 50 #include "ui/views/controls/label.h" |
49 #include "ui/views/layout/layout_constants.h" | 51 #include "ui/views/layout/layout_constants.h" |
50 #include "ui/views/resources/grit/views_resources.h" | 52 #include "ui/views/resources/grit/views_resources.h" |
51 #include "ui/views/views_delegate.h" | 53 #include "ui/views/views_delegate.h" |
52 #include "ui/views/widget/root_view.h" | 54 #include "ui/views/widget/root_view.h" |
53 #include "ui/views/window/frame_background.h" | 55 #include "ui/views/window/frame_background.h" |
54 #include "ui/views/window/window_shape.h" | 56 #include "ui/views/window/window_shape.h" |
55 | 57 |
56 #if defined(OS_LINUX) | 58 #if defined(OS_LINUX) |
57 #include "ui/views/controls/menu/menu_runner.h" | 59 #include "ui/views/controls/menu/menu_runner.h" |
58 #endif | 60 #endif |
59 | 61 |
| 62 #if defined(OS_WIN) |
| 63 #include "base/win/windows_version.h" |
| 64 #endif |
| 65 |
60 using content::WebContents; | 66 using content::WebContents; |
61 | 67 |
62 namespace { | 68 namespace { |
63 | 69 |
64 // In the window corners, the resize areas don't actually expand bigger, but the | 70 // In the window corners, the resize areas don't actually expand bigger, but the |
65 // 16 px at the end of each edge triggers diagonal resizing. | 71 // 16 px at the end of each edge triggers diagonal resizing. |
66 const int kResizeAreaCornerSize = 16; | 72 const int kResizeAreaCornerSize = 16; |
67 | 73 |
68 #if !defined(OS_WIN) | 74 #if !defined(OS_WIN) |
69 // The icon never shrinks below 16 px on a side. | 75 // The icon never shrinks below 16 px on a side. |
70 const int kIconMinimumSize = 16; | 76 const int kIconMinimumSize = 16; |
71 #endif | 77 #endif |
72 | 78 |
| 79 // This draws button that look like win10 window caption buttons. The |
| 80 // foreground colour is taken from the theme itself, so that it is guaranteed |
| 81 // to provide good contrast with the background. |
| 82 class OpaqueWin10CaptionButton : public views::CustomButton { |
| 83 public: |
| 84 OpaqueWin10CaptionButton(OpaqueBrowserFrameView* parent, ViewID view_id); |
| 85 |
| 86 // The width and height of a caption button. The button is slightly shorter |
| 87 // when the browser window is maximized since there is less vertical space. |
| 88 const int kWidth = 46; |
| 89 const int kHeightNormal = 28; |
| 90 const int kHeightMaximized = 20; |
| 91 |
| 92 private: |
| 93 // Overridden from View: |
| 94 gfx::Size GetPreferredSize() const override; |
| 95 void OnBoundsChanged(const gfx::Rect& previous_bounds) override; |
| 96 void OnPaint(gfx::Canvas* canvas) override; |
| 97 |
| 98 OpaqueBrowserFrameView* parent_; |
| 99 gfx::Size preferred_size_; |
| 100 |
| 101 DISALLOW_COPY_AND_ASSIGN(OpaqueWin10CaptionButton); |
| 102 }; |
| 103 |
| 104 OpaqueWin10CaptionButton::OpaqueWin10CaptionButton( |
| 105 OpaqueBrowserFrameView* parent, |
| 106 ViewID view_id) |
| 107 : views::CustomButton(parent), |
| 108 parent_(parent), |
| 109 preferred_size_(kWidth, kHeightNormal) { |
| 110 set_id(view_id); |
| 111 } |
| 112 |
| 113 gfx::Size OpaqueWin10CaptionButton::GetPreferredSize() const { |
| 114 return preferred_size_; |
| 115 } |
| 116 |
| 117 void OpaqueWin10CaptionButton::OnBoundsChanged( |
| 118 const gfx::Rect& previous_bounds) { |
| 119 views::Widget* widget = GetWidget(); |
| 120 if (!widget) |
| 121 return; |
| 122 |
| 123 preferred_size_.set_height( |
| 124 widget->IsMaximized() ? kHeightMaximized : kHeightNormal); |
| 125 PreferredSizeChanged(); |
| 126 } |
| 127 |
| 128 void OpaqueWin10CaptionButton::OnPaint(gfx::Canvas* canvas) { |
| 129 gfx::Rect rect(GetLocalBounds()); |
| 130 |
| 131 // Determine the foreground colour. The colour is chosen to most contrast |
| 132 // with the frame's background colour. |
| 133 SkColor foreground = SK_ColorTRANSPARENT; |
| 134 SkColor foreground_secondary = SK_ColorTRANSPARENT; |
| 135 SkColor frame_color = parent_->GetFrameColor(); |
| 136 if (color_utils::GetContrastRatio(frame_color, SK_ColorBLACK) > |
| 137 color_utils::kMinimumReadableContrastRatio) { |
| 138 foreground = SK_ColorBLACK; |
| 139 foreground_secondary = SkColorSetA(SK_ColorWHITE, 100); |
| 140 } else { |
| 141 foreground = SK_ColorWHITE; |
| 142 foreground_secondary = SkColorSetA(SK_ColorBLACK, 100); |
| 143 } |
| 144 |
| 145 // Determine the background colour depending on which caption button is being |
| 146 // painted and its current state. |
| 147 SkColor background = SK_ColorTRANSPARENT; |
| 148 if (id() == VIEW_ID_CLOSE_BUTTON) { |
| 149 // The close button has an opaque red background on hover, slightly |
| 150 // less saturated on press. |
| 151 SkAlpha alpha = 0; |
| 152 if (state() == STATE_HOVERED) { |
| 153 foreground = SK_ColorWHITE; |
| 154 foreground_secondary = SK_ColorTRANSPARENT; |
| 155 alpha = hover_animation_->is_animating() ? |
| 156 hover_animation_->CurrentValueBetween(0, 255) : 255; |
| 157 background = SkColorSetARGB(alpha, 232, 17, 35); |
| 158 } else if (state() == STATE_PRESSED) { |
| 159 foreground = SK_ColorWHITE; |
| 160 foreground_secondary = SK_ColorTRANSPARENT; |
| 161 background = SkColorSetARGB(255, 241, 112, 122); |
| 162 } |
| 163 } else { |
| 164 if (state() == STATE_HOVERED) { |
| 165 int alpha = hover_animation_->is_animating() ? |
| 166 hover_animation_->CurrentValueBetween(0, 50) : 50; |
| 167 if (foreground == SK_ColorWHITE) { |
| 168 // Background is dark, so lighten it. |
| 169 background = SkColorSetA(SK_ColorWHITE, alpha); |
| 170 } else { |
| 171 // Background is light, so darken it. |
| 172 background = SkColorSetA(SK_ColorBLACK, alpha); |
| 173 } |
| 174 } else if (state() == STATE_PRESSED) { |
| 175 if (foreground == SK_ColorWHITE) { |
| 176 // Background is dark, so lighten it. |
| 177 background = SkColorSetA(SK_ColorWHITE, 70); |
| 178 } else { |
| 179 // Background is light, so darken it. |
| 180 background = SkColorSetA(SK_ColorBLACK, 70); |
| 181 } |
| 182 } |
| 183 } |
| 184 |
| 185 // Fill the background of the button if needed. |
| 186 //if (background != SK_ColorTRANSPARENT) |
| 187 // canvas->FillRect(GetLocalBounds(), background); |
| 188 |
| 189 SkPaint paint; |
| 190 paint.setStyle(SkPaint::kStroke_Style); |
| 191 paint.setStrokeWidth(SkIntToScalar(1)); |
| 192 paint.setStrokeCap(SkPaint::kSquare_Cap); |
| 193 paint.setColor(foreground); |
| 194 |
| 195 SkPaint paint_secondary; |
| 196 paint_secondary.setStyle(SkPaint::kStroke_Style); |
| 197 paint_secondary.setStrokeWidth(SkIntToScalar(3)); |
| 198 paint_secondary.setStrokeCap(SkPaint::kSquare_Cap); |
| 199 paint_secondary.setColor(foreground_secondary); |
| 200 |
| 201 ui::NativeTheme::Part native_part = ui::NativeTheme::kCaptionMin; |
| 202 switch(id()) { |
| 203 case VIEW_ID_MINIMIZE_BUTTON: |
| 204 break; |
| 205 case VIEW_ID_MAXIMIZE_BUTTON: |
| 206 native_part = ui::NativeTheme::kCaptionMax; |
| 207 break; |
| 208 case VIEW_ID_RESTORE_BUTTON: |
| 209 native_part = ui::NativeTheme::kCaptionRestore; |
| 210 break; |
| 211 case VIEW_ID_CLOSE_BUTTON: |
| 212 native_part = ui::NativeTheme::kCaptionClose; |
| 213 break; |
| 214 default: |
| 215 NOTREACHED(); |
| 216 break; |
| 217 } |
| 218 |
| 219 ui::NativeTheme::State native_state = ui::NativeTheme::kNormal; |
| 220 switch(state()) { |
| 221 case STATE_NORMAL: |
| 222 break; |
| 223 case STATE_HOVERED: |
| 224 native_state = ui::NativeTheme::kHovered; |
| 225 break; |
| 226 case STATE_PRESSED: |
| 227 native_state = ui::NativeTheme::kPressed; |
| 228 break; |
| 229 case STATE_DISABLED: |
| 230 native_state = ui::NativeTheme::kDisabled; |
| 231 break; |
| 232 default: |
| 233 NOTREACHED(); |
| 234 break; |
| 235 } |
| 236 |
| 237 ui::NativeTheme::ExtraParams extra; |
| 238 GetNativeTheme()->Paint(canvas->sk_canvas(), |
| 239 native_part, |
| 240 native_state, |
| 241 rect, |
| 242 extra); |
| 243 // Draw the button's icon. |
| 244 /*switch (id()) { |
| 245 case VIEW_ID_MINIMIZE_BUTTON: { |
| 246 rect.ClampToCenteredSize(gfx::Size(9, 9)); |
| 247 int mid_y = rect.CenterPoint().y(); |
| 248 gfx::Point p1(rect.x(), mid_y); |
| 249 gfx::Point p2(rect.right(), mid_y); |
| 250 canvas->DrawLine(p1, p2, paint_secondary); |
| 251 canvas->DrawLine(p1, p2, paint); |
| 252 break; |
| 253 } |
| 254 case VIEW_ID_MAXIMIZE_BUTTON: |
| 255 rect.ClampToCenteredSize(gfx::Size(9, 9)); |
| 256 canvas->DrawRect(rect, paint_secondary); |
| 257 canvas->DrawRect(rect, paint); |
| 258 break; |
| 259 case VIEW_ID_RESTORE_BUTTON: { |
| 260 rect.ClampToCenteredSize(gfx::Size(7, 7)); |
| 261 rect.Offset(1, -1); |
| 262 gfx::Point start(rect.origin()); |
| 263 start.Offset(0, 2); |
| 264 gfx::Point stop(rect.bottom_right()); |
| 265 stop.Offset(-2, 0); |
| 266 |
| 267 canvas->DrawLine(rect.origin(), rect.top_right(), paint_secondary); |
| 268 canvas->DrawLine(rect.top_right(), rect.bottom_right(), paint_secondary); |
| 269 |
| 270 canvas->DrawLine(start, rect.origin(), paint); |
| 271 canvas->DrawLine(rect.origin(), rect.top_right(), paint); |
| 272 canvas->DrawLine(rect.top_right(), rect.bottom_right(), paint); |
| 273 canvas->DrawLine(rect.bottom_right(), stop, paint); |
| 274 |
| 275 rect.Offset(-2, 2); |
| 276 canvas->DrawRect(rect, paint_secondary); |
| 277 canvas->DrawRect(rect, paint); |
| 278 break; |
| 279 } |
| 280 case VIEW_ID_CLOSE_BUTTON: |
| 281 rect.ClampToCenteredSize(gfx::Size(9, 9)); |
| 282 paint.setAntiAlias(true); |
| 283 paint_secondary.setAntiAlias(true); |
| 284 canvas->DrawLine(rect.origin(), rect.bottom_right(), paint_secondary); |
| 285 canvas->DrawLine(rect.bottom_left(), rect.top_right(), paint_secondary); |
| 286 canvas->DrawLine(rect.origin(), rect.bottom_right(), paint); |
| 287 canvas->DrawLine(rect.bottom_left(), rect.top_right(), paint); |
| 288 break; |
| 289 }*/ |
| 290 } |
| 291 |
73 } // namespace | 292 } // namespace |
74 | 293 |
75 /////////////////////////////////////////////////////////////////////////////// | 294 /////////////////////////////////////////////////////////////////////////////// |
76 // OpaqueBrowserFrameView, public: | 295 // OpaqueBrowserFrameView, public: |
77 | 296 |
78 OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame, | 297 OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame, |
79 BrowserView* browser_view) | 298 BrowserView* browser_view) |
80 : BrowserNonClientFrameView(frame, browser_view), | 299 : BrowserNonClientFrameView(frame, browser_view), |
81 layout_(new OpaqueBrowserFrameViewLayout(this)), | 300 layout_(new OpaqueBrowserFrameViewLayout(this)), |
82 minimize_button_(nullptr), | 301 minimize_button_(nullptr), |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 // Claim |rect| if it is in a non-tab portion of the tabstrip. | 729 // Claim |rect| if it is in a non-tab portion of the tabstrip. |
511 return tabstrip->IsRectInWindowCaption(rect_in_tabstrip_coords); | 730 return tabstrip->IsRectInWindowCaption(rect_in_tabstrip_coords); |
512 } | 731 } |
513 | 732 |
514 // We claim |rect| because it is above the bottom of the tabstrip, but | 733 // We claim |rect| because it is above the bottom of the tabstrip, but |
515 // not in the tabstrip itself. In particular, the avatar label/button is left | 734 // not in the tabstrip itself. In particular, the avatar label/button is left |
516 // of the tabstrip and the window controls are right of the tabstrip. | 735 // of the tabstrip and the window controls are right of the tabstrip. |
517 return true; | 736 return true; |
518 } | 737 } |
519 | 738 |
520 views::ImageButton* OpaqueBrowserFrameView::InitWindowCaptionButton( | 739 views::CustomButton* OpaqueBrowserFrameView::InitWindowCaptionButton( |
521 int normal_image_id, | 740 int normal_image_id, |
522 int hot_image_id, | 741 int hot_image_id, |
523 int pushed_image_id, | 742 int pushed_image_id, |
524 int mask_image_id, | 743 int mask_image_id, |
525 int accessibility_string_id, | 744 int accessibility_string_id, |
526 ViewID view_id) { | 745 ViewID view_id) { |
527 views::ImageButton* button = new views::ImageButton(this); | 746 views::CustomButton* button = nullptr; |
528 const ui::ThemeProvider* tp = frame()->GetThemeProvider(); | 747 const ui::ThemeProvider* tp = frame()->GetThemeProvider(); |
529 button->SetImage(views::CustomButton::STATE_NORMAL, | 748 |
530 tp->GetImageSkiaNamed(normal_image_id)); | 749 #if defined(OS_WIN) |
531 button->SetImage(views::CustomButton::STATE_HOVERED, | 750 if (base::win::GetVersion() <= base::win::VERSION_VISTA) {//base::win::VERSION
_WIN10) { |
532 tp->GetImageSkiaNamed(hot_image_id)); | 751 #endif |
533 button->SetImage(views::CustomButton::STATE_PRESSED, | 752 views::ImageButton* image_button = new views::ImageButton(this); |
534 tp->GetImageSkiaNamed(pushed_image_id)); | 753 image_button->SetImage(views::CustomButton::STATE_NORMAL, |
535 if (browser_view()->IsBrowserTypeNormal()) { | 754 tp->GetImageSkiaNamed(normal_image_id)); |
536 button->SetBackground( | 755 image_button->SetImage(views::CustomButton::STATE_HOVERED, |
537 tp->GetColor(ThemeProperties::COLOR_BUTTON_BACKGROUND), | 756 tp->GetImageSkiaNamed(hot_image_id)); |
538 tp->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND), | 757 image_button->SetImage(views::CustomButton::STATE_PRESSED, |
539 tp->GetImageSkiaNamed(mask_image_id)); | 758 tp->GetImageSkiaNamed(pushed_image_id)); |
| 759 if (browser_view()->IsBrowserTypeNormal()) { |
| 760 image_button->SetBackground( |
| 761 tp->GetColor(ThemeProperties::COLOR_BUTTON_BACKGROUND), |
| 762 tp->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND), |
| 763 tp->GetImageSkiaNamed(mask_image_id)); |
| 764 } |
| 765 image_button->SetAccessibleName( |
| 766 l10n_util::GetStringUTF16(accessibility_string_id)); |
| 767 image_button->set_id(view_id); |
| 768 button = image_button; |
| 769 #if defined(OS_WIN) |
| 770 } else { |
| 771 OpaqueWin10CaptionButton* opaque_button = |
| 772 new OpaqueWin10CaptionButton(this, view_id); |
| 773 button = opaque_button; |
540 } | 774 } |
541 button->SetAccessibleName( | 775 #endif |
542 l10n_util::GetStringUTF16(accessibility_string_id)); | 776 |
543 button->set_id(view_id); | |
544 AddChildView(button); | 777 AddChildView(button); |
545 return button; | 778 return button; |
546 } | 779 } |
547 | 780 |
548 int OpaqueBrowserFrameView::FrameBorderThickness(bool restored) const { | 781 int OpaqueBrowserFrameView::FrameBorderThickness(bool restored) const { |
549 return layout_->FrameBorderThickness(restored); | 782 return layout_->FrameBorderThickness(restored); |
550 } | 783 } |
551 | 784 |
552 int OpaqueBrowserFrameView::NonClientBorderThickness() const { | 785 int OpaqueBrowserFrameView::NonClientBorderThickness() const { |
553 return layout_->NonClientBorderThickness(); | 786 return layout_->NonClientBorderThickness(); |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
827 gfx::Rect side(x, y, kClientEdgeThickness, h); | 1060 gfx::Rect side(x, y, kClientEdgeThickness, h); |
828 canvas->FillRect(side, color); | 1061 canvas->FillRect(side, color); |
829 if (draw_bottom) { | 1062 if (draw_bottom) { |
830 canvas->FillRect(gfx::Rect(x, y + h, w + (2 * kClientEdgeThickness), | 1063 canvas->FillRect(gfx::Rect(x, y + h, w + (2 * kClientEdgeThickness), |
831 kClientEdgeThickness), | 1064 kClientEdgeThickness), |
832 color); | 1065 color); |
833 } | 1066 } |
834 side.Offset(w + kClientEdgeThickness, 0); | 1067 side.Offset(w + kClientEdgeThickness, 0); |
835 canvas->FillRect(side, color); | 1068 canvas->FillRect(side, color); |
836 } | 1069 } |
OLD | NEW |