blob: 81f2ea33749337ee73892a5721469f9eabd28770 [file] [log] [blame]
// Copyright 2013 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/caption_buttons/frame_caption_button_container_view.h"
#include "ash/ash_switches.h"
#include "ash/test/ash_test_base.h"
#include "base/command_line.h"
#include "grit/ash_resources.h"
#include "ui/aura/root_window.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace ash {
namespace {
class TestWidgetDelegate : public views::WidgetDelegateView {
public:
TestWidgetDelegate(bool can_maximize) : can_maximize_(can_maximize) {
}
virtual ~TestWidgetDelegate() {
}
virtual bool CanMaximize() const OVERRIDE {
return can_maximize_;
}
private:
bool can_maximize_;
DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate);
};
} // namespace
class FrameCaptionButtonContainerViewTest : public ash::test::AshTestBase {
public:
enum MaximizeAllowed {
MAXIMIZE_ALLOWED,
MAXIMIZE_DISALLOWED
};
FrameCaptionButtonContainerViewTest() {
}
virtual ~FrameCaptionButtonContainerViewTest() {
}
// Creates a widget which allows maximizing based on |maximize_allowed|.
// The caller takes ownership of the returned widget.
views::Widget* CreateTestWidget(
MaximizeAllowed maximize_allowed) WARN_UNUSED_RESULT {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params;
params.delegate = new TestWidgetDelegate(
maximize_allowed == MAXIMIZE_ALLOWED);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.context = CurrentContext();
widget->Init(params);
return widget;
}
// Tests that |leftmost| and |rightmost| are at |container|'s edges.
bool CheckButtonsAtEdges(FrameCaptionButtonContainerView* container,
const views::CustomButton& leftmost,
const views::CustomButton& rightmost) {
gfx::Rect expected(container->GetPreferredSize());
expected.Inset(container->GetLeftInset(), 0, container->GetRightInset(), 0);
gfx::Rect container_size(container->GetPreferredSize());
if (leftmost.y() == rightmost.y() &&
leftmost.height() == rightmost.height() &&
leftmost.x() == expected.x() &&
leftmost.y() == expected.y() &&
leftmost.height() == expected.height() &&
rightmost.bounds().right() == expected.right()) {
return true;
}
LOG(ERROR) << "Buttons " << leftmost.bounds().ToString() << " "
<< rightmost.bounds().ToString() << " not at edges of "
<< expected.ToString();
return false;
}
private:
DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTest);
};
class FrameCaptionButtonContainerViewTestOldStyle
: public FrameCaptionButtonContainerViewTest {
public:
FrameCaptionButtonContainerViewTestOldStyle() {
}
virtual ~FrameCaptionButtonContainerViewTestOldStyle() {
}
// Returns true if the images for |button|'s states match the passed in ids.
bool ImagesMatch(views::CustomButton* custom_button,
int normal_image_id,
int hovered_image_id,
int pressed_image_id) {
views::ImageButton* button =
static_cast<views::ImageButton*>(custom_button);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
gfx::ImageSkia* normal = rb.GetImageSkiaNamed(normal_image_id);
gfx::ImageSkia* hovered = rb.GetImageSkiaNamed(hovered_image_id);
gfx::ImageSkia* pressed = rb.GetImageSkiaNamed(pressed_image_id);
using views::Button;
gfx::ImageSkia actual_normal = button->GetImage(Button::STATE_NORMAL);
gfx::ImageSkia actual_hovered = button->GetImage(Button::STATE_HOVERED);
gfx::ImageSkia actual_pressed = button->GetImage(Button::STATE_PRESSED);
return actual_normal.BackedBySameObjectAs(*normal) &&
actual_hovered.BackedBySameObjectAs(*hovered) &&
actual_pressed.BackedBySameObjectAs(*pressed);
}
virtual void SetUp() OVERRIDE {
FrameCaptionButtonContainerViewTest::SetUp();
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAshDisableAlternateFrameCaptionButtonStyle);
}
private:
DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTestOldStyle);
};
// Test how the allowed actions affect which caption buttons are visible.
TEST_F(FrameCaptionButtonContainerViewTestOldStyle, ButtonVisibility) {
// The minimize button should be hidden when both minimizing and maximizing
// are allowed because the size button can do both.
scoped_ptr<views::Widget> widget_can_maximize(
CreateTestWidget(MAXIMIZE_ALLOWED));
FrameCaptionButtonContainerView container1(widget_can_maximize.get(),
FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
container1.Layout();
FrameCaptionButtonContainerView::TestApi t1(&container1);
EXPECT_FALSE(t1.minimize_button()->visible());
EXPECT_TRUE(t1.size_button()->visible());
EXPECT_TRUE(t1.close_button()->visible());
EXPECT_TRUE(CheckButtonsAtEdges(
&container1, *t1.size_button(), *t1.close_button()));
// The minimize button should be visible when minimizing is allowed but
// maximizing is disallowed.
scoped_ptr<views::Widget> widget_cannot_maximize(
CreateTestWidget(MAXIMIZE_DISALLOWED));
FrameCaptionButtonContainerView container2(widget_cannot_maximize.get(),
FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
container2.Layout();
FrameCaptionButtonContainerView::TestApi t2(&container2);
EXPECT_TRUE(t2.minimize_button()->visible());
EXPECT_FALSE(t2.size_button()->visible());
EXPECT_TRUE(t2.close_button()->visible());
EXPECT_TRUE(CheckButtonsAtEdges(
&container2, *t2.minimize_button(), *t2.close_button()));
// Neither the minimize button nor the size button should be visible when
// neither minimizing nor maximizing are allowed.
FrameCaptionButtonContainerView container3(widget_cannot_maximize.get(),
FrameCaptionButtonContainerView::MINIMIZE_DISALLOWED);
container3.Layout();
FrameCaptionButtonContainerView::TestApi t3(&container3);
EXPECT_FALSE(t3.minimize_button()->visible());
EXPECT_FALSE(t3.size_button()->visible());
EXPECT_TRUE(t3.close_button()->visible());
EXPECT_TRUE(CheckButtonsAtEdges(
&container3, *t3.close_button(), *t3.close_button()));
}
// Test the layout when a border is set on the container.
TEST_F(FrameCaptionButtonContainerViewTestOldStyle, LayoutBorder) {
const int kTopInset = 1;
const int kLeftInset = 2;
const int kBottomInset = 3;
const int kRightInset = 4;
scoped_ptr<views::Widget> widget(CreateTestWidget(MAXIMIZE_ALLOWED));
FrameCaptionButtonContainerView container(widget.get(),
FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
container.set_border(views::Border::CreateEmptyBorder(
kTopInset, kLeftInset, kBottomInset, kRightInset));
container.Layout();
FrameCaptionButtonContainerView::TestApi t(&container);
EXPECT_EQ(kLeftInset, t.size_button()->x());
EXPECT_EQ(kTopInset, t.close_button()->y());
EXPECT_EQ(container.GetPreferredSize().height(),
t.close_button()->bounds().bottom() + kBottomInset);
EXPECT_EQ(container.GetPreferredSize().width(),
t.close_button()->bounds().right() + kRightInset);
}
// Test how the header style affects which images are used for the buttons.
TEST_F(FrameCaptionButtonContainerViewTestOldStyle, HeaderStyle) {
scoped_ptr<views::Widget> widget(CreateTestWidget(MAXIMIZE_ALLOWED));
FrameCaptionButtonContainerView container(widget.get(),
FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
FrameCaptionButtonContainerView::TestApi t(&container);
// Tall header style.
container.set_header_style(
FrameCaptionButtonContainerView::HEADER_STYLE_TALL);
container.Layout();
EXPECT_TRUE(ImagesMatch(t.size_button(),
IDR_AURA_WINDOW_MAXIMIZE,
IDR_AURA_WINDOW_MAXIMIZE_H,
IDR_AURA_WINDOW_MAXIMIZE_P));
EXPECT_TRUE(ImagesMatch(t.close_button(),
IDR_AURA_WINDOW_CLOSE,
IDR_AURA_WINDOW_CLOSE_H,
IDR_AURA_WINDOW_CLOSE_P));
// Short header style.
container.set_header_style(
FrameCaptionButtonContainerView::HEADER_STYLE_SHORT);
container.Layout();
EXPECT_TRUE(ImagesMatch(t.size_button(),
IDR_AURA_WINDOW_MAXIMIZED_RESTORE,
IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H,
IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P));
EXPECT_TRUE(ImagesMatch(t.close_button(),
IDR_AURA_WINDOW_MAXIMIZED_CLOSE,
IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H,
IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P));
// Maximized short header style.
widget->Maximize();
container.Layout();
EXPECT_TRUE(ImagesMatch(t.size_button(),
IDR_AURA_WINDOW_MAXIMIZED_RESTORE2,
IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H,
IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P));
EXPECT_TRUE(ImagesMatch(t.close_button(),
IDR_AURA_WINDOW_MAXIMIZED_CLOSE2,
IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H,
IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P));
// The buttons are visible during a reveal of the top-of-window views in
// immersive fullscreen. They should use the same images as maximized.
widget->SetFullscreen(true);
container.Layout();
EXPECT_TRUE(ImagesMatch(t.size_button(),
IDR_AURA_WINDOW_MAXIMIZED_RESTORE2,
IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H,
IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P));
EXPECT_TRUE(ImagesMatch(t.close_button(),
IDR_AURA_WINDOW_MAXIMIZED_CLOSE2,
IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H,
IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P));
// AppNonClientFrameViewAsh has a dedicated set of images.
container.set_header_style(
FrameCaptionButtonContainerView::HEADER_STYLE_MAXIMIZED_HOSTED_APP);
container.Layout();
EXPECT_TRUE(ImagesMatch(t.size_button(),
IDR_AURA_WINDOW_FULLSCREEN_RESTORE,
IDR_AURA_WINDOW_FULLSCREEN_RESTORE_H,
IDR_AURA_WINDOW_FULLSCREEN_RESTORE_P));
EXPECT_TRUE(ImagesMatch(t.close_button(),
IDR_AURA_WINDOW_FULLSCREEN_CLOSE,
IDR_AURA_WINDOW_FULLSCREEN_CLOSE_H,
IDR_AURA_WINDOW_FULLSCREEN_CLOSE_P));
}
class FrameCaptionButtonContainerViewTestAlternateStyle
: public FrameCaptionButtonContainerViewTest {
public:
FrameCaptionButtonContainerViewTestAlternateStyle() {
}
virtual ~FrameCaptionButtonContainerViewTestAlternateStyle() {
}
virtual void SetUp() OVERRIDE {
FrameCaptionButtonContainerViewTest::SetUp();
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAshEnableAlternateFrameCaptionButtonStyle);
ASSERT_TRUE(switches::UseAlternateFrameCaptionButtonStyle());
}
private:
DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTestAlternateStyle);
};
// Test how the alternate button style affects which buttons are visible in the
// default case.
TEST_F(FrameCaptionButtonContainerViewTestAlternateStyle, ButtonVisibility) {
// Both the minimize button and the maximize button should be visible when
// both minimizing and maximizing are allowed when using the alternate
// button style.
scoped_ptr<views::Widget> widget_can_maximize(
CreateTestWidget(MAXIMIZE_ALLOWED));
FrameCaptionButtonContainerView container(widget_can_maximize.get(),
FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
container.Layout();
FrameCaptionButtonContainerView::TestApi t(&container);
EXPECT_TRUE(t.minimize_button()->visible());
EXPECT_TRUE(t.size_button()->visible());
EXPECT_TRUE(t.close_button()->visible());
EXPECT_TRUE(CheckButtonsAtEdges(
&container, *t.minimize_button(), *t.close_button()));
}
} // namespace ash