| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/wm/dialog_frame_view.h" |
| |
| #include "grit/ui_resources.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/font.h" |
| #include "ui/gfx/image/image.h" |
| #include "ui/gfx/insets.h" |
| #include "ui/views/background.h" |
| #include "ui/views/border.h" |
| #include "ui/views/controls/button/image_button.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/widget/widget_delegate.h" |
| |
| namespace { |
| |
| // TODO(benrg): Make frame shadow and stroke agree with the spec. |
| |
| // TODO(benrg): Title bar text should be #222, not black. Text in the client |
| // area should also be #222, but is currently usually black. Punting on this |
| // until the overhaul of color handling that will be happening Real Soon Now. |
| const SkColor kDialogTitleColor = SK_ColorBLACK; |
| const SkColor kDialogBackgroundColor = SK_ColorWHITE; |
| |
| // Dialog-size-dependent padding values from the spec, in pixels. |
| const int kGoogleSmallDialogVPadding = 16; |
| const int kGoogleSmallDialogHPadding = 20; |
| const int kGoogleMediumDialogVPadding = 28; |
| const int kGoogleMediumDialogHPadding = 32; |
| const int kGoogleLargeDialogVPadding = 30; |
| const int kGoogleLargeDialogHPadding = 42; |
| |
| // Dialog layouts themselves contain some padding, which should be ignored in |
| // favor of the padding values above. Currently we hack it by nudging the |
| // client area outward. |
| const int kDialogHPaddingNudge = 13; |
| const int kDialogTopPaddingNudge = 5; |
| const int kDialogBottomPaddingNudge = 10; |
| |
| // TODO(benrg): There are no examples in the spec of close boxes on medium- or |
| // small-size dialogs, and the close button size is not factored into other |
| // sizing decisions. This value could cause problems with smaller dialogs. |
| const int kCloseButtonSize = 44; |
| |
| const gfx::Font& GetTitleFont() { |
| static gfx::Font* title_font = NULL; |
| if (!title_font) |
| title_font = new gfx::Font(gfx::Font().DeriveFont(4, gfx::Font::NORMAL)); |
| return *title_font; |
| } |
| |
| } // namespace |
| |
| namespace ash { |
| namespace internal { |
| |
| // static |
| const char DialogFrameView::kViewClassName[] = "ash/wm/DialogFrameView"; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // DialogFrameView, public: |
| |
| DialogFrameView::DialogFrameView() { |
| set_background(views::Background::CreateSolidBackground( |
| kDialogBackgroundColor)); |
| |
| ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| close_button_ = new views::ImageButton(this); |
| close_button_->SetImage(views::CustomButton::BS_NORMAL, |
| rb.GetImageNamed(IDR_CLOSE_BAR).ToImageSkia()); |
| close_button_->SetImage(views::CustomButton::BS_HOT, |
| rb.GetImageNamed(IDR_CLOSE_BAR_H).ToImageSkia()); |
| close_button_->SetImage(views::CustomButton::BS_PUSHED, |
| rb.GetImageNamed(IDR_CLOSE_BAR_P).ToImageSkia()); |
| close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, |
| views::ImageButton::ALIGN_MIDDLE); |
| AddChildView(close_button_); |
| } |
| |
| DialogFrameView::~DialogFrameView() { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // DialogFrameView, views::NonClientFrameView: |
| |
| gfx::Rect DialogFrameView::GetBoundsForClientView() const { |
| gfx::Rect client_bounds = GetLocalBounds(); |
| client_bounds.Inset(GetClientInsets()); |
| return client_bounds; |
| } |
| |
| gfx::Rect DialogFrameView::GetWindowBoundsForClientBounds( |
| const gfx::Rect& client_bounds) const { |
| gfx::Rect window_bounds = client_bounds; |
| window_bounds.Inset(-GetClientInsets()); |
| return window_bounds; |
| } |
| |
| int DialogFrameView::NonClientHitTest(const gfx::Point& point) { |
| if (close_button_->GetMirroredBounds().Contains(point)) |
| return HTCLOSE; |
| return point.y() < GetClientInsets().top() ? HTCAPTION : HTCLIENT; |
| } |
| |
| void DialogFrameView::GetWindowMask(const gfx::Size& size, |
| gfx::Path* window_mask) { |
| // Nothing to do. |
| } |
| |
| void DialogFrameView::ResetWindowControls() { |
| // Nothing to do. |
| } |
| |
| void DialogFrameView::UpdateWindowIcon() { |
| // Nothing to do. |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // DialogFrameView, views::View overrides: |
| |
| std::string DialogFrameView::GetClassName() const { |
| return kViewClassName; |
| } |
| |
| void DialogFrameView::Layout() { |
| title_display_rect_ = GetLocalBounds(); |
| title_display_rect_.Inset(GetPaddingInsets()); |
| title_display_rect_.set_height(GetTitleFont().GetHeight()); |
| |
| // The hot rectangle for the close button is flush with the upper right of the |
| // dialog. The close button image is smaller, and is centered in the hot rect. |
| close_button_->SetBounds( |
| width() - kCloseButtonSize, |
| 0, kCloseButtonSize, kCloseButtonSize); |
| } |
| |
| void DialogFrameView::OnPaint(gfx::Canvas* canvas) { |
| views::View::OnPaint(canvas); |
| views::WidgetDelegate* delegate = GetWidget()->widget_delegate(); |
| if (!delegate) |
| return; |
| canvas->DrawStringInt(delegate->GetWindowTitle(), GetTitleFont(), |
| kDialogTitleColor, title_display_rect_); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // DialogFrameView, views::ButtonListener overrides: |
| |
| void DialogFrameView::ButtonPressed(views::Button* sender, |
| const views::Event& event) { |
| if (sender == close_button_) |
| GetWidget()->Close(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // DialogFrameView, private: |
| |
| gfx::Insets DialogFrameView::GetPaddingInsets() const { |
| // These three discrete padding sizes come from the spec. If we ever wanted |
| // our Google-style dialogs to be resizable, we would probably need to |
| // smoothly interpolate the padding size instead. |
| int v_padding, h_padding; |
| if (width() <= 280) { |
| v_padding = kGoogleSmallDialogVPadding; |
| h_padding = kGoogleSmallDialogHPadding; |
| } else if (width() <= 480) { |
| v_padding = kGoogleMediumDialogVPadding; |
| h_padding = kGoogleMediumDialogHPadding; |
| } else { |
| v_padding = kGoogleLargeDialogVPadding; |
| h_padding = kGoogleLargeDialogHPadding; |
| } |
| return gfx::Insets(v_padding, h_padding, v_padding, h_padding); |
| } |
| |
| gfx::Insets DialogFrameView::GetClientInsets() const { |
| gfx::Insets insets = GetPaddingInsets(); |
| // The title should be separated from the client area by 1 em (dialog spec), |
| // and one em is equal to the font size (CSS spec). |
| insets += gfx::Insets( |
| GetTitleFont().GetHeight() + GetTitleFont().GetFontSize() - |
| kDialogTopPaddingNudge, |
| -kDialogHPaddingNudge, |
| -kDialogBottomPaddingNudge, |
| -kDialogHPaddingNudge); |
| return insets; |
| } |
| |
| } // namespace internal |
| } // namespace views |