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