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 "ash/wm/dialog_frame_view.h" | 5 #include "ash/wm/dialog_frame_view.h" |
6 | 6 |
| 7 #include "grit/ui_resources_standard.h" |
7 #include "ui/base/hit_test.h" | 8 #include "ui/base/hit_test.h" |
| 9 #include "ui/base/resource/resource_bundle.h" |
8 #include "ui/gfx/canvas.h" | 10 #include "ui/gfx/canvas.h" |
9 #include "ui/gfx/font.h" | 11 #include "ui/gfx/font.h" |
| 12 #include "ui/gfx/insets.h" |
10 #include "ui/views/background.h" | 13 #include "ui/views/background.h" |
11 #include "ui/views/border.h" | 14 #include "ui/views/border.h" |
| 15 #include "ui/views/controls/button/image_button.h" |
12 #include "ui/views/widget/widget.h" | 16 #include "ui/views/widget/widget.h" |
13 #include "ui/views/widget/widget_delegate.h" | 17 #include "ui/views/widget/widget_delegate.h" |
14 | 18 |
| 19 namespace { |
| 20 |
| 21 // TODO(benrg): Make frame shadow and stroke agree with the spec. |
| 22 |
| 23 // TODO(benrg): Title bar text should be #222, not black. Text in the client |
| 24 // area should also be #222, but is currently usually black. Punting on this |
| 25 // until the overhaul of color handling that will be happening Real Soon Now. |
| 26 const SkColor kDialogTitleColor = SK_ColorBLACK; |
| 27 const SkColor kDialogBackgroundColor = SK_ColorWHITE; |
| 28 |
| 29 // Dialog-size-dependent padding values from the spec, in pixels. |
| 30 const int kGoogleSmallDialogVPadding = 16; |
| 31 const int kGoogleSmallDialogHPadding = 20; |
| 32 const int kGoogleMediumDialogVPadding = 28; |
| 33 const int kGoogleMediumDialogHPadding = 32; |
| 34 const int kGoogleLargeDialogVPadding = 30; |
| 35 const int kGoogleLargeDialogHPadding = 42; |
| 36 |
| 37 // Dialog layouts themselves contain some padding, which should be ignored in |
| 38 // favor of the padding values above. Currently we hack it by nudging the |
| 39 // client area outward. |
| 40 const int kDialogHPaddingNudge = 13; |
| 41 const int kDialogTopPaddingNudge = 5; |
| 42 const int kDialogBottomPaddingNudge = 10; |
| 43 |
| 44 // TODO(benrg): There are no examples in the spec of close boxes on medium- or |
| 45 // small-size dialogs, and the close button size is not factored into other |
| 46 // sizing decisions. This value could cause problems with smaller dialogs. |
| 47 const int kCloseButtonSize = 44; |
| 48 |
| 49 } // namespace |
| 50 |
15 namespace ash { | 51 namespace ash { |
16 namespace internal { | 52 namespace internal { |
17 | 53 |
18 // static | 54 // static |
19 const char DialogFrameView::kViewClassName[] = "ash/wm/DialogFrameView"; | 55 const char DialogFrameView::kViewClassName[] = "ash/wm/DialogFrameView"; |
20 | 56 |
21 // static | 57 // static |
22 gfx::Font* DialogFrameView::title_font_ = NULL; | 58 gfx::Font* DialogFrameView::title_font_ = NULL; |
23 | 59 |
24 // TODO(benrg): tweak these values until they match Google-style. | |
25 // TODO(benrg): this may also mean tweaking the frame shadow opacity. | |
26 const SkColor kDialogBackgroundColor = SK_ColorWHITE; | |
27 // const SkColor kDialogBorderColor = SkColorSetRGB(0xCC, 0xCC, 0xCC); | |
28 const SkColor kDialogTitleColor = SK_ColorBLACK; | |
29 | |
30 // TODO(benrg): Replace with width-based padding heuristic. | |
31 // |kDialogPadding| is the standardized padding amount, the specific per-side | |
32 // padding values are offset from this to achieve a uniform look with our | |
33 // existing code. | |
34 static int kDialogPadding = 30; | |
35 static int kDialogHPadding = kDialogPadding - 13; | |
36 static int kDialogTopPadding = kDialogPadding; | |
37 static int kDialogBottomPadding = kDialogPadding - 10; | |
38 static int kDialogContentVSpacing = 5; | |
39 | |
40 const int kCloseButtonSize = 16; | |
41 | |
42 //////////////////////////////////////////////////////////////////////////////// | 60 //////////////////////////////////////////////////////////////////////////////// |
43 // DialogFrameView, public: | 61 // DialogFrameView, public: |
44 | 62 |
45 DialogFrameView::DialogFrameView() { | 63 DialogFrameView::DialogFrameView() { |
46 set_background(views::Background::CreateSolidBackground( | 64 set_background(views::Background::CreateSolidBackground( |
47 kDialogBackgroundColor)); | 65 kDialogBackgroundColor)); |
48 if (!title_font_) | 66 if (!title_font_) |
49 title_font_ = new gfx::Font(gfx::Font().DeriveFont(4, gfx::Font::NORMAL)); | 67 title_font_ = new gfx::Font(gfx::Font().DeriveFont(4, gfx::Font::NORMAL)); |
| 68 |
| 69 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 70 close_button_ = new views::ImageButton(this); |
| 71 close_button_->SetImage(views::CustomButton::BS_NORMAL, |
| 72 rb.GetBitmapNamed(IDR_CLOSE_BAR)); |
| 73 close_button_->SetImage(views::CustomButton::BS_HOT, |
| 74 rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); |
| 75 close_button_->SetImage(views::CustomButton::BS_PUSHED, |
| 76 rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); |
| 77 close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, |
| 78 views::ImageButton::ALIGN_MIDDLE); |
| 79 AddChildView(close_button_); |
50 } | 80 } |
51 | 81 |
52 DialogFrameView::~DialogFrameView() { | 82 DialogFrameView::~DialogFrameView() { |
53 } | 83 } |
54 | 84 |
55 //////////////////////////////////////////////////////////////////////////////// | 85 //////////////////////////////////////////////////////////////////////////////// |
56 // DialogFrameView, views::NonClientFrameView: | 86 // DialogFrameView, views::NonClientFrameView: |
57 | 87 |
58 gfx::Rect DialogFrameView::GetBoundsForClientView() const { | 88 gfx::Rect DialogFrameView::GetBoundsForClientView() const { |
59 gfx::Rect client_bounds = GetLocalBounds(); | 89 gfx::Rect client_bounds = GetLocalBounds(); |
60 client_bounds.Inset(kDialogHPadding, GetNonClientTopHeight(), | 90 client_bounds.Inset(GetClientInsets()); |
61 kDialogHPadding, kDialogBottomPadding); | |
62 return client_bounds; | 91 return client_bounds; |
63 } | 92 } |
64 | 93 |
65 gfx::Rect DialogFrameView::GetWindowBoundsForClientBounds( | 94 gfx::Rect DialogFrameView::GetWindowBoundsForClientBounds( |
66 const gfx::Rect& client_bounds) const { | 95 const gfx::Rect& client_bounds) const { |
67 gfx::Rect window_bounds = client_bounds; | 96 gfx::Rect window_bounds = client_bounds; |
68 window_bounds.Inset(-kDialogHPadding, -GetNonClientTopHeight(), | 97 window_bounds.Inset(-GetClientInsets()); |
69 -kDialogHPadding, -kDialogBottomPadding); | |
70 return window_bounds; | 98 return window_bounds; |
71 } | 99 } |
72 | 100 |
73 int DialogFrameView::NonClientHitTest(const gfx::Point& point) { | 101 int DialogFrameView::NonClientHitTest(const gfx::Point& point) { |
74 if (close_button_rect_.Contains(point)) | 102 if (close_button_->GetMirroredBounds().Contains(point)) |
75 return HTCLOSE; | 103 return HTCLOSE; |
76 return point.y() < GetNonClientTopHeight() ? HTCAPTION : HTCLIENT; | 104 return point.y() < GetClientInsets().top() ? HTCAPTION : HTCLIENT; |
77 } | 105 } |
78 | 106 |
79 void DialogFrameView::GetWindowMask(const gfx::Size& size, | 107 void DialogFrameView::GetWindowMask(const gfx::Size& size, |
80 gfx::Path* window_mask) { | 108 gfx::Path* window_mask) { |
81 // Nothing to do. | 109 // Nothing to do. |
82 } | 110 } |
83 | 111 |
84 void DialogFrameView::ResetWindowControls() { | 112 void DialogFrameView::ResetWindowControls() { |
85 // Nothing to do. | 113 // Nothing to do. |
86 } | 114 } |
87 | 115 |
88 void DialogFrameView::UpdateWindowIcon() { | 116 void DialogFrameView::UpdateWindowIcon() { |
89 // Nothing to do. | 117 // Nothing to do. |
90 } | 118 } |
91 | 119 |
92 //////////////////////////////////////////////////////////////////////////////// | 120 //////////////////////////////////////////////////////////////////////////////// |
93 // DialogFrameView, views::View overrides: | 121 // DialogFrameView, views::View overrides: |
94 | 122 |
95 std::string DialogFrameView::GetClassName() const { | 123 std::string DialogFrameView::GetClassName() const { |
96 return kViewClassName; | 124 return kViewClassName; |
97 } | 125 } |
98 | 126 |
99 void DialogFrameView::Layout() { | 127 void DialogFrameView::Layout() { |
100 title_display_rect_ = GetLocalBounds(); | 128 title_display_rect_ = GetLocalBounds(); |
101 // TODO(benrg): size based on font height rather than bottom padding. | 129 title_display_rect_.Inset(GetPaddingInsets()); |
102 close_button_rect_.SetRect(width() - kDialogPadding - kCloseButtonSize, | |
103 kDialogTopPadding, kCloseButtonSize, | |
104 kCloseButtonSize); | |
105 title_display_rect_.Inset(kDialogPadding, kDialogTopPadding, | |
106 kDialogPadding + kCloseButtonSize, | |
107 kDialogBottomPadding); | |
108 title_display_rect_.set_height(title_font_->GetHeight()); | 130 title_display_rect_.set_height(title_font_->GetHeight()); |
| 131 |
| 132 // The hot rectangle for the close button is flush with the upper right of the |
| 133 // dialog. The close button image is smaller, and is centered in the hot rect. |
| 134 close_button_->SetBounds( |
| 135 width() - kCloseButtonSize, |
| 136 0, kCloseButtonSize, kCloseButtonSize); |
109 } | 137 } |
110 | 138 |
111 void DialogFrameView::OnPaint(gfx::Canvas* canvas) { | 139 void DialogFrameView::OnPaint(gfx::Canvas* canvas) { |
112 views::View::OnPaint(canvas); | 140 views::View::OnPaint(canvas); |
113 canvas->FillRect(SK_ColorRED, close_button_rect_); | |
114 views::WidgetDelegate* delegate = GetWidget()->widget_delegate(); | 141 views::WidgetDelegate* delegate = GetWidget()->widget_delegate(); |
115 if (!delegate) | 142 if (!delegate) |
116 return; | 143 return; |
117 canvas->DrawStringInt(delegate->GetWindowTitle(), *title_font_, | 144 canvas->DrawStringInt(delegate->GetWindowTitle(), *title_font_, |
118 kDialogTitleColor, title_display_rect_); | 145 kDialogTitleColor, title_display_rect_); |
119 } | 146 } |
120 | 147 |
121 // TODO(benrg): You may want to use a views::Button for the close box instead. | 148 //////////////////////////////////////////////////////////////////////////////// |
122 bool DialogFrameView::OnMousePressed(const views::MouseEvent& event) { | 149 // DialogFrameView, views::ButtonListener overrides: |
123 if (close_button_rect_.Contains(event.location())) | 150 |
124 return true; | 151 void DialogFrameView::ButtonPressed(views::Button* sender, |
125 return View::OnMousePressed(event); | 152 const views::Event& event) { |
126 } | 153 if (sender == close_button_) |
127 void DialogFrameView::OnMouseReleased(const views::MouseEvent& event) { | |
128 if (close_button_rect_.Contains(event.location())) | |
129 GetWidget()->Close(); | 154 GetWidget()->Close(); |
130 } | 155 } |
131 | 156 |
132 //////////////////////////////////////////////////////////////////////////////// | 157 //////////////////////////////////////////////////////////////////////////////// |
133 // DialogFrameView, private: | 158 // DialogFrameView, private: |
134 | 159 |
135 int DialogFrameView::GetNonClientTopHeight() const { | 160 gfx::Insets DialogFrameView::GetPaddingInsets() const { |
136 return kDialogTopPadding + title_font_->GetHeight() + kDialogContentVSpacing; | 161 // These three discrete padding sizes come from the spec. If we ever wanted |
| 162 // our Google-style dialogs to be resizable, we would probably need to |
| 163 // smoothly interpolate the padding size instead. |
| 164 int v_padding, h_padding; |
| 165 if (width() <= 280) { |
| 166 v_padding = kGoogleSmallDialogVPadding; |
| 167 h_padding = kGoogleSmallDialogHPadding; |
| 168 } else if (width() <= 480) { |
| 169 v_padding = kGoogleMediumDialogVPadding; |
| 170 h_padding = kGoogleMediumDialogHPadding; |
| 171 } else { |
| 172 v_padding = kGoogleLargeDialogVPadding; |
| 173 h_padding = kGoogleLargeDialogHPadding; |
| 174 } |
| 175 return gfx::Insets(v_padding, h_padding, v_padding, h_padding); |
| 176 } |
| 177 |
| 178 gfx::Insets DialogFrameView::GetClientInsets() const { |
| 179 gfx::Insets insets = GetPaddingInsets(); |
| 180 // The title should be separated from the client area by 1 em (dialog spec), |
| 181 // and one em is equal to the font size (CSS spec). |
| 182 insets += gfx::Insets( |
| 183 title_font_->GetHeight() + title_font_->GetFontSize() - |
| 184 kDialogTopPaddingNudge, |
| 185 -kDialogHPaddingNudge, |
| 186 -kDialogBottomPaddingNudge, |
| 187 -kDialogHPaddingNudge); |
| 188 return insets; |
137 } | 189 } |
138 | 190 |
139 } // namespace internal | 191 } // namespace internal |
140 } // namespace views | 192 } // namespace views |
OLD | NEW |