Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: chrome/browser/ui/views/frame/opaque_browser_frame_view.cc

Issue 1431303002: Make windows caption buttons look natural on windows 10 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698