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

Side by Side Diff: ui/views/style/mac/dialog_button_border_mac.cc

Issue 1569113002: MacViews: Style BUTTON_STYLE buttons using the "modern" UI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: respond to comments, desktop linux 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "ui/views/style/mac/dialog_button_border_mac.h" 5 #include "ui/views/style/mac/dialog_button_border_mac.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "skia/ext/refptr.h" 8 #include "skia/ext/refptr.h"
9 #include "third_party/skia/include/core/SkCanvas.h" 9 #include "third_party/skia/include/core/SkCanvas.h"
10 #include "third_party/skia/include/core/SkDrawLooper.h" 10 #include "third_party/skia/include/core/SkDrawLooper.h"
11 #include "third_party/skia/include/core/SkPaint.h" 11 #include "third_party/skia/include/core/SkPaint.h"
12 #include "third_party/skia/include/core/SkPath.h" 12 #include "third_party/skia/include/core/SkPath.h"
13 #include "third_party/skia/include/effects/SkGradientShader.h" 13 #include "third_party/skia/include/effects/SkGradientShader.h"
14 #include "ui/gfx/canvas.h" 14 #include "ui/gfx/canvas.h"
15 #include "ui/native_theme/native_theme_mac.h"
15 #include "ui/views/border.h" 16 #include "ui/views/border.h"
16 #include "ui/views/controls/button/custom_button.h" 17 #include "ui/views/controls/button/custom_button.h"
18 #include "ui/views/controls/button/label_button.h"
19
20 using ui::NativeThemeMac;
17 21
18 namespace views { 22 namespace views {
19 namespace { 23 namespace {
20 24
21 // Type to map button states to a corresponding SkColor.
22 typedef const SkColor ColorByState[Button::STATE_COUNT];
23
24 // If a state is added, ColorByState will silently fill with zeros, so assert.
25 static_assert(Button::STATE_COUNT == 4,
26 "DialogButtonBorderMac assumes 4 button states.");
27
28 // Corner radius of rounded rectangles. 25 // Corner radius of rounded rectangles.
29 const SkScalar kCornerRadius = 2; 26 const SkScalar kCornerRadius = 2;
27 const SkScalar kFocusCornerRadius = 4;
28 const SkScalar kFocusRingThickness = 3;
30 29
31 // Vertical offset of the drop shadow and the inner highlight shadow. 30 const SkColor kDefaultBorderColor = SkColorSetARGB(0xF2, 0xBA, 0xBA, 0xBA);
32 const SkScalar kShadowOffsetY = 1; 31 const SkColor kHighlightedBorderColor = SkColorSetARGB(0xFF, 0x52, 0x76, 0xFF);
33 32 const SkColor kFocusRingColor = SkColorSetARGB(0x80, 0x3B, 0x9A, 0xFC);
34 // Shadow blur radius of the inner highlight shadow.
35 const double kInnerShadowBlurRadius = 2.0;
36 33
37 // Default border insets, to provide text padding. 34 // Default border insets, to provide text padding.
38 const int kPaddingX = 14; 35 const int kPaddingX = 19;
39 const int kPaddingY = 4; 36 const int kPaddingY = 7;
40 37
41 sk_sp<SkShader> CreateButtonGradient(int height, 38 void DrawDialogButtonBackground(const SkRect& button_rect,
42 Button::ButtonState state) { 39 SkCanvas* canvas,
43 ColorByState start = {0xFFF0F0F0, 0xFFF4F4F4, 0xFFEBEBEB, 0xFFEDEDED}; 40 const CustomButton& button) {
44 ColorByState end = {0xFFE0E0E0, 0xFFE4E4E4, 0xFFDBDBDB, 0xFFDEDEDE};
45
46 SkPoint gradient_points[2];
47 gradient_points[0].iset(0, 0);
48 gradient_points[1].iset(0, height);
49
50 SkColor gradient_colors[] = {start[state], start[state], end[state]};
51 SkScalar gradient_positions[] = {0.0, 0.38, 1.0};
52
53 return SkGradientShader::MakeLinear(
54 gradient_points, gradient_colors, gradient_positions, 3,
55 SkShader::kClamp_TileMode);
56 }
57
58 void DrawConstrainedButtonBackground(const SkRect& button_rect,
59 SkCanvas* canvas,
60 Button::ButtonState button_state) {
61 // Extend the size of the SkRect so the border stroke is drawn over it on all 41 // Extend the size of the SkRect so the border stroke is drawn over it on all
62 // sides. 42 // sides.
63 SkRect rect(button_rect); 43 SkRect rect(button_rect);
64 rect.fRight += 1; 44 rect.fRight += 1;
65 rect.fBottom += 1; 45 rect.fBottom += 1;
66 46
67 SkPaint paint; 47 NativeThemeMac::BackgroundType type = NativeThemeMac::BackgroundType::NORMAL;
68 48 if (!button.enabled() || button.state() == Button::STATE_DISABLED)
69 // Drop Shadow. 49 type = NativeThemeMac::BackgroundType::DISABLED;
70 ColorByState shadow = {0x14000000, 0x1F000000, 0x00000000, 0x00000000}; 50 else if (button.state() == Button::STATE_PRESSED)
71 const double blur = 0.0; 51 type = NativeThemeMac::BackgroundType::PRESSED;
72 std::vector<gfx::ShadowValue> shadows( 52 else if (DialogButtonBorderMac::ShowsDefault(button))
73 1, gfx::ShadowValue(gfx::Vector2d(0, kShadowOffsetY), blur, 53 type = NativeThemeMac::BackgroundType::HIGHLIGHTED;
74 shadow[button_state]));
75 paint.setLooper(gfx::CreateShadowDrawLooper(shadows));
76 54
77 // Background. 55 // Background.
78 paint.setShader(CreateButtonGradient(rect.height(), button_state)); 56 SkPaint paint;
57 paint.setShader(
58 NativeThemeMac::GetButtonBackgroundShader(type, rect.height()));
79 paint.setStyle(SkPaint::kFill_Style); 59 paint.setStyle(SkPaint::kFill_Style);
80 paint.setFlags(SkPaint::kAntiAlias_Flag); 60 paint.setFlags(SkPaint::kAntiAlias_Flag);
81 canvas->drawRoundRect(rect, kCornerRadius, kCornerRadius, paint); 61 canvas->drawRoundRect(rect, kCornerRadius, kCornerRadius, paint);
82 } 62 }
83 63
84 // Draws an inner box shadow inside a rounded rectangle of size |rect|. The 64 } // namespace
85 // technique: draw a black "ring" around the outside of the button cell. Then
86 // clip out everything except the shadow it casts. Works similar to Blink's
87 // GraphicsContext::drawInnerShadow().
88 void DrawRoundRectInnerShadow(const SkRect& rect,
89 SkCanvas* canvas,
90 SkColor shadow_color) {
91 const gfx::Vector2d shadow_offset(0, kShadowOffsetY);
92 SkRect outer(rect);
93 outer.outset(abs(shadow_offset.x()) + kInnerShadowBlurRadius,
94 abs(shadow_offset.y()) + kInnerShadowBlurRadius);
95 65
96 SkPath path; 66 // static
97 path.addRect(outer); 67 bool DialogButtonBorderMac::ShowsDefault(const CustomButton& button) {
98 path.setFillType(SkPath::kEvenOdd_FillType); 68 const LabelButton* label_button = CustomButton::AsLabelButton(&button);
99 path.addRoundRect(rect, kCornerRadius, kCornerRadius); // Poke a hole. 69 if (!label_button || !label_button->is_default())
70 return false;
100 71
101 // Inset the clip to cater for the border stroke. 72 // TODO(tapted): Check whether the Widget is active, and only return true here
102 SkPath clip; 73 // if it is. Plumbing this requires default buttons to also observe Widget
103 clip.addRoundRect(rect.makeInset(0.5, 0.5), kCornerRadius, kCornerRadius); 74 // activations to ensure text and background colors are properly invalidated.
104 75 return true;
105 SkPaint paint;
106 std::vector<gfx::ShadowValue> shadows(
107 1, gfx::ShadowValue(shadow_offset, kInnerShadowBlurRadius, shadow_color));
108 paint.setLooper(gfx::CreateShadowDrawLooper(shadows));
109 paint.setStyle(SkPaint::kFill_Style);
110 paint.setColor(SK_ColorBLACK); // Note: Entirely clipped.
111
112 canvas->save();
113 canvas->clipPath(clip, SkRegion::kIntersect_Op, true /* antialias */);
114 canvas->drawPath(path, paint);
115 canvas->restore();
116 } 76 }
117 77
118 } // namespace
119
120 DialogButtonBorderMac::DialogButtonBorderMac() { 78 DialogButtonBorderMac::DialogButtonBorderMac() {
121 set_insets(gfx::Insets(kPaddingY, kPaddingX, kPaddingY, kPaddingX)); 79 set_insets(gfx::Insets(kPaddingY, kPaddingX, kPaddingY, kPaddingX));
122 } 80 }
123 81
124 DialogButtonBorderMac::~DialogButtonBorderMac() {} 82 DialogButtonBorderMac::~DialogButtonBorderMac() {}
125 83
126 void DialogButtonBorderMac::Paint(const View& view, gfx::Canvas* canvas) { 84 void DialogButtonBorderMac::Paint(const View& view, gfx::Canvas* canvas) {
127 DCHECK(CustomButton::AsCustomButton(&view)); 85 DCHECK(CustomButton::AsCustomButton(&view));
128 const CustomButton& button = static_cast<const CustomButton&>(view); 86 const CustomButton& button = static_cast<const CustomButton&>(view);
129 SkCanvas* canvas_skia = canvas->sk_canvas(); 87 SkCanvas* canvas_skia = canvas->sk_canvas();
130 88
131 // Inset all sides for the rounded rectangle stroke. Inset again to make room 89 // Inset all sides for the rounded rectangle stroke. Inset again to make room
132 // for the shadows (while keeping the text centered). 90 // for the shadows and static focus ring (while keeping the text centered).
133 SkRect sk_rect = gfx::RectToSkRect(view.GetLocalBounds()); 91 SkRect sk_rect = gfx::RectToSkRect(view.GetLocalBounds());
134 sk_rect.inset(2.0, 2.0); 92 sk_rect.inset(kFocusRingThickness, kFocusRingThickness);
135 93
136 DrawConstrainedButtonBackground(sk_rect, canvas_skia, button.state()); 94 DrawDialogButtonBackground(sk_rect, canvas_skia, button);
137 95
138 // Offset so that strokes are contained within the pixel boundary. 96 // Offset so that strokes are contained within the pixel boundary.
139 sk_rect.offset(0.5, 0.5); 97 sk_rect.offset(0.5, 0.5);
140 ColorByState highlight = {0xBFFFFFFF, 0xF2FFFFFF, 0x24000000, 0x00000000};
141 DrawRoundRectInnerShadow(sk_rect, canvas_skia, highlight[button.state()]);
142 98
143 // Border or focus ring. 99 // Border and focus ring.
100 SkColor border_color = kDefaultBorderColor;
101 if (button.state() == Button::STATE_PRESSED || ShowsDefault(button))
102 border_color = kHighlightedBorderColor;
103
144 SkPaint paint; 104 SkPaint paint;
145 ColorByState border = {0x40000000, 0x4D000000, 0x4D000000, 0x1F000000};
146 const SkColor focus_border = {0xFF5DA5FF};
147 paint.setStrokeWidth(1);
148 paint.setStyle(SkPaint::kStroke_Style); 105 paint.setStyle(SkPaint::kStroke_Style);
149 paint.setFlags(SkPaint::kAntiAlias_Flag); 106 paint.setFlags(SkPaint::kAntiAlias_Flag);
150 if (button.HasFocus() && button.state() != Button::STATE_PRESSED) 107 paint.setStrokeWidth(1);
151 paint.setColor(focus_border); 108 paint.setColor(border_color);
152 else
153 paint.setColor(border[button.state()]);
154 canvas_skia->drawRoundRect(sk_rect, kCornerRadius, kCornerRadius, paint); 109 canvas_skia->drawRoundRect(sk_rect, kCornerRadius, kCornerRadius, paint);
110
111 if (button.HasFocus()) {
112 paint.setStrokeWidth(kFocusRingThickness);
113 paint.setColor(kFocusRingColor);
114 sk_rect.inset(-1, -1);
115 canvas_skia->drawRoundRect(sk_rect, kFocusCornerRadius, kFocusCornerRadius,
116 paint);
117 }
155 } 118 }
156 119
157 gfx::Size DialogButtonBorderMac::GetMinimumSize() const { 120 gfx::Size DialogButtonBorderMac::GetMinimumSize() const {
158 return gfx::Size(100, 30); 121 return gfx::Size(28, 4);
159 } 122 }
160 123
161 } // namespace views 124 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698