Commit 7f39bb69 authored by msw@google.com's avatar msw@google.com

Implement rough new dialog style.

Add/update and use NativeTheme dialog colors for Win/Aura.
Use Label[Button] and Bubble[Border|Background] in DialogFrameView.
Add DialogFrameView::content_margins_ similar to BubbleFrameView.

Increase widget example size, add DialogExample with title.
Tweak dialog example InitParams (nix frame, make transparent).
Make the buttons in the widget example focusable.
Make LabelButton::GetPreferredSize public.
Refactor BubbleFrameView::GetBoundsForClientView.

Roughly matches the specification at:
https://docs.google.com/a/google.com/file/d/0B6x6iYCtKinEVjFvOWNfRlJCLU0/edit
See the screenshot on the bug at:
https://code.google.com/p/chromium/issues/detail?id=166075#c5

TODO(followup): Investigate a minor LabelButton drag/hot issue.
TODO(followup): Add/use new close (x) button resources.
TODO(followup): Generalize BubbleBorder to a custom frame border?

BUG=166075
TEST=[Views examples] dialogs look closer to mocks with --enable-new-dialog-style (actual Chrome dialogs need more work).
R=sky@chromium.org

Review URL: https://codereview.chromium.org/11756005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175411 0039d316-1c4b-4281-b951-d872f2087c98
parent 01b054ac
......@@ -647,7 +647,7 @@ views::NonClientFrameView* Shell::CreateDefaultNonClientFrameView(
views::Widget* widget) {
if (CommandLine::ForCurrentProcess()->HasSwitch(
::switches::kEnableNewDialogStyle)) {
return new views::DialogFrameView;
return new views::DialogFrameView(string16());
}
// Use translucent-style window frames for dialogs.
CustomFrameViewAsh* frame_view = new CustomFrameViewAsh;
......
......@@ -22,6 +22,8 @@ const SkColor kMenuBackgroundColor = SK_ColorWHITE;
const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128);
// Windows:
const SkColor kWindowBackgroundColor = SK_ColorWHITE;
// Dialogs:
const SkColor kDialogBackgroundColor = SkColorSetRGB(251, 251, 251);
// FocusableBorder:
const SkColor kFocusedBorderColor = SkColorSetRGB(0x4D, 0x90, 0xFE);
const SkColor kUnfocusedBorderColor = SkColorSetRGB(0xD9, 0xD9, 0xD9);
......@@ -90,7 +92,7 @@ SkColor NativeThemeAura::GetSystemColor(ColorId color_id) const {
// Dialogs
case kColorId_DialogBackground:
return kWindowBackgroundColor;
return kDialogBackgroundColor;
// FocusableBorder
case kColorId_FocusedBorderColor:
......
......@@ -34,7 +34,7 @@ namespace {
// Theme colors returned by GetSystemColor().
const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128);
// Dialogs:
const SkColor kDialogBackgroundColor = SkColorSetRGB(200, 200, 200);
const SkColor kDialogBackgroundColor = SkColorSetRGB(251, 251, 251);
// FocusableBorder:
const SkColor kFocusedBorderColor = SkColorSetRGB(0x4d, 0x90, 0xfe);
const SkColor kUnfocusedBorderColor = SkColorSetRGB(0xd9, 0xd9, 0xd9);
......@@ -460,9 +460,7 @@ SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
// Dialogs
case kColorId_DialogBackground:
// TODO(benrg): Should this use the new Windows theme functions? The old
// code in DialogClientView::OnPaint used GetSysColor(COLOR_3DFACE).
return system_colors_[COLOR_3DFACE];
return kDialogBackgroundColor;
// FocusableBorder
case kColorId_FocusedBorderColor:
......
......@@ -49,11 +49,10 @@ BubbleFrameView::BubbleFrameView(const gfx::Insets& margins,
BubbleFrameView::~BubbleFrameView() {}
gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
gfx::Insets margin = bubble_border()->GetInsets();
margin += content_margins();
return gfx::Rect(margin.left(), margin.top(),
std::max(width() - margin.width(), 0),
std::max(height() - margin.height(), 0));
gfx::Rect client_bounds = GetLocalBounds();
client_bounds.Inset(border()->GetInsets());
client_bounds.Inset(content_margins());
return client_bounds;
}
gfx::Rect BubbleFrameView::GetWindowBoundsForClientBounds(
......
......@@ -125,6 +125,34 @@ void LabelButton::SetNativeTheme(bool native_theme) {
ResetColorsFromNativeTheme();
}
gfx::Size LabelButton::GetPreferredSize() {
// Resize multi-line labels paired with images to use their available width.
const gfx::Size image_size(image_->GetPreferredSize());
if (GetTextMultiLine() && !image_size.IsEmpty() && !GetText().empty() &&
GetHorizontalAlignment() == gfx::ALIGN_CENTER) {
label_->SizeToFit(GetLocalBounds().width() - image_size.width() - kSpacing);
}
// Calculate the required size.
gfx::Size size(label_->GetPreferredSize());
if (image_size.width() > 0 && size.width() > 0)
size.Enlarge(kSpacing, 0);
size.set_height(std::max(size.height(), image_size.height()));
size.Enlarge(image_size.width() + GetInsets().width(), GetInsets().height());
// Increase the minimum size monotonically with the preferred size.
size.SetSize(std::max(min_size_.width(), size.width()),
std::max(min_size_.height(), size.height()));
min_size_ = size;
// Return the largest known size clamped to the maximum size (if valid).
if (max_size_.width() > 0)
size.set_width(std::min(max_size_.width(), size.width()));
if (max_size_.height() > 0)
size.set_height(std::min(max_size_.height(), size.height()));
return size;
}
void LabelButton::ResetColorsFromNativeTheme() {
const ui::NativeTheme* theme = GetNativeTheme();
SkColor colors[STATE_COUNT] = {
......@@ -157,34 +185,6 @@ void LabelButton::StateChanged() {
Layout();
}
gfx::Size LabelButton::GetPreferredSize() {
// Resize multi-line labels paired with images to use their available width.
const gfx::Size image_size(image_->GetPreferredSize());
if (GetTextMultiLine() && !image_size.IsEmpty() && !GetText().empty() &&
GetHorizontalAlignment() == gfx::ALIGN_CENTER) {
label_->SizeToFit(GetLocalBounds().width() - image_size.width() - kSpacing);
}
// Calculate the required size.
gfx::Size size(label_->GetPreferredSize());
if (image_size.width() > 0 && size.width() > 0)
size.Enlarge(kSpacing, 0);
size.set_height(std::max(size.height(), image_size.height()));
size.Enlarge(image_size.width() + GetInsets().width(), GetInsets().height());
// Increase the minimum size monotonically with the preferred size.
size.SetSize(std::max(min_size_.width(), size.width()),
std::max(min_size_.height(), size.height()));
min_size_ = size;
// Return the largest known size clamped to the maximum size (if valid).
if (max_size_.width() > 0)
size.set_width(std::min(max_size_.width(), size.width()));
if (max_size_.height() > 0)
size.set_height(std::min(max_size_.height(), size.height()));
return size;
}
void LabelButton::Layout() {
gfx::Rect child_area(GetLocalBounds());
child_area.Inset(GetInsets());
......
......@@ -60,6 +60,9 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
bool native_theme() const { return native_theme_; }
void SetNativeTheme(bool native_theme);
// Overridden from View:
virtual gfx::Size GetPreferredSize() OVERRIDE;
private:
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Init);
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Label);
......@@ -74,7 +77,6 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
virtual void StateChanged() OVERRIDE;
// Overridden from View:
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual void Layout() OVERRIDE;
virtual std::string GetClassName() const OVERRIDE;
virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
......
......@@ -14,6 +14,19 @@
namespace views {
namespace examples {
namespace {
class DialogExample : public DialogDelegateView {
public:
virtual string16 GetWindowTitle() const OVERRIDE;
};
string16 DialogExample::GetWindowTitle() const {
return ASCIIToUTF16("Dialog Widget Example");
}
} // namespace
WidgetExample::WidgetExample() : ExampleBase("Widget") {
}
......@@ -34,6 +47,7 @@ void WidgetExample::BuildButton(View* container,
const std::string& label,
int tag) {
TextButton* button = new TextButton(this, ASCIIToUTF16(label));
button->set_focusable(true);
button->set_tag(tag);
container->AddChildView(button);
}
......@@ -42,7 +56,7 @@ void WidgetExample::ShowWidget(View* sender, Widget::InitParams params) {
// Setup shared Widget heirarchy and bounds parameters.
params.parent = sender->GetWidget()->GetNativeView();
params.bounds = gfx::Rect(sender->GetBoundsInScreen().CenterPoint(),
gfx::Size(200, 100));
gfx::Size(300, 200));
Widget* widget = new Widget();
widget->Init(params);
......@@ -66,7 +80,9 @@ void WidgetExample::ButtonPressed(Button* sender, const ui::Event& event) {
break;
case DIALOG: {
Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
params.delegate = new DialogDelegateView();
params.delegate = new DialogExample();
params.remove_standard_frame = true;
params.transparent = true;
ShowWidget(sender, params);
break;
}
......
......@@ -106,7 +106,7 @@ ClientView* DialogDelegate::CreateClientView(Widget* widget) {
}
NonClientFrameView* DialogDelegate::CreateNonClientFrameView(Widget* widget) {
return UseNewStyle() ? new DialogFrameView() :
return UseNewStyle() ? new DialogFrameView(GetWindowTitle()) :
WidgetDelegate::CreateNonClientFrameView(widget);
}
......
......@@ -12,66 +12,56 @@
#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/bubble/bubble_border.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/dialog_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;
// The base spacing value, multiples of which are used in various places.
const int kSpacing = 10;
// static
const char kViewClassName[] = "ui/views/DialogFrameView";
} // namespace
namespace views {
// static
const char DialogFrameView::kViewClassName[] = "ui/views/DialogFrameView";
////////////////////////////////////////////////////////////////////////////////
// DialogFrameView, public:
DialogFrameView::DialogFrameView() {
set_background(Background::CreateSolidBackground(kDialogBackgroundColor));
DialogFrameView::DialogFrameView(const string16& title)
: title_(NULL),
close_(NULL) {
BubbleBorder* border =
new BubbleBorder(BubbleBorder::FLOAT, BubbleBorder::SMALL_SHADOW);
border->set_background_color(GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_DialogBackground));
set_border(border);
// Update the background, which relies on the border.
set_background(new BubbleBackground(border));
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
title_font_.reset(new gfx::Font(rb.GetFont(ui::ResourceBundle::MediumFont)));
close_button_ = new views::ImageButton(this);
close_button_->SetImage(views::CustomButton::STATE_NORMAL,
rb.GetImageNamed(IDR_CLOSE_BAR).ToImageSkia());
close_button_->SetImage(CustomButton::STATE_HOVERED,
rb.GetImageNamed(IDR_CLOSE_BAR_H).ToImageSkia());
close_button_->SetImage(CustomButton::STATE_PRESSED,
rb.GetImageNamed(IDR_CLOSE_BAR_P).ToImageSkia());
close_button_->SetImageAlignment(ImageButton::ALIGN_CENTER,
ImageButton::ALIGN_MIDDLE);
AddChildView(close_button_);
title_ = new Label(title, rb.GetFont(ui::ResourceBundle::MediumFont));
title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(title_);
close_ = new LabelButton(this, string16());
close_->SetImage(CustomButton::STATE_NORMAL,
*rb.GetImageNamed(IDR_CLOSE_BAR).ToImageSkia());
close_->SetImage(CustomButton::STATE_HOVERED,
*rb.GetImageNamed(IDR_CLOSE_BAR_H).ToImageSkia());
close_->SetImage(CustomButton::STATE_PRESSED,
*rb.GetImageNamed(IDR_CLOSE_BAR_P).ToImageSkia());
close_->SetSize(close_->GetPreferredSize());
AddChildView(close_);
// Set the margins for the content view.
content_margins_ = gfx::Insets(2 * kSpacing + title_->font().GetHeight(),
2 * kSpacing, 2 * kSpacing, 2 * kSpacing);
}
DialogFrameView::~DialogFrameView() {
......@@ -94,26 +84,22 @@ gfx::Rect DialogFrameView::GetWindowBoundsForClientBounds(
}
int DialogFrameView::NonClientHitTest(const gfx::Point& point) {
if (close_button_->GetMirroredBounds().Contains(point))
if (close_->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.
}
void DialogFrameView::UpdateWindowTitle() {
// Nothing to do.
}
////////////////////////////////////////////////////////////////////////////////
......@@ -124,65 +110,28 @@ std::string DialogFrameView::GetClassName() const {
}
void DialogFrameView::Layout() {
title_display_rect_ = GetLocalBounds();
title_display_rect_.Inset(GetPaddingInsets());
title_display_rect_.set_height(title_font_->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) {
View::OnPaint(canvas);
WidgetDelegate* delegate = GetWidget()->widget_delegate();
if (!delegate)
return;
canvas->DrawStringInt(delegate->GetWindowTitle(), *title_font_.get(),
kDialogTitleColor, title_display_rect_);
gfx::Rect bounds = GetLocalBounds();
bounds.Inset(border()->GetInsets());
close_->SetPosition(gfx::Point(bounds.right() - close_->width(), bounds.y()));
bounds.Inset(gfx::Insets(kSpacing, 2 * kSpacing, 0, close_->width()));
bounds.set_height(title_->font().GetHeight());
title_->SetBoundsRect(bounds);
}
////////////////////////////////////////////////////////////////////////////////
// DialogFrameView, ButtonListener overrides:
void DialogFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == close_button_)
if (sender == close_)
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(
title_font_->GetHeight() + title_font_->GetFontSize() -
kDialogTopPaddingNudge,
-kDialogHPaddingNudge,
-kDialogBottomPaddingNudge,
-kDialogHPaddingNudge);
gfx::Insets insets = border()->GetInsets();
insets += content_margins_;
return insets;
}
......
......@@ -8,22 +8,16 @@
#include "ui/views/controls/button/button.h"
#include "ui/views/window/non_client_view.h"
namespace gfx {
class Font;
}
namespace views {
class ImageButton;
class Label;
class LabelButton;
// A NonClientFrameView that implements a new-style for dialogs.
class VIEWS_EXPORT DialogFrameView : public NonClientFrameView,
public ButtonListener {
public:
// Internal class name.
static const char kViewClassName[];
DialogFrameView();
explicit DialogFrameView(const string16& title);
virtual ~DialogFrameView();
// Overridden from NonClientFrameView:
......@@ -40,19 +34,18 @@ class VIEWS_EXPORT DialogFrameView : public NonClientFrameView,
// Overridden from View:
virtual std::string GetClassName() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
// Overridden from ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
private:
gfx::Insets GetPaddingInsets() const;
gfx::Insets GetClientInsets() const;
scoped_ptr<gfx::Font> title_font_;
gfx::Rect title_display_rect_;
Label* title_;
LabelButton* close_;
ImageButton* close_button_;
// The margins between the content and the inside of the border.
gfx::Insets content_margins_;
DISALLOW_COPY_AND_ASSIGN(DialogFrameView);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment