Commit 53f18455 authored by jonross@chromium.org's avatar jonross@chromium.org

Linux Aura Task Manager Frame Buttons Misaligned

The task manager is a CustomFrameView. This had the logic for its button
placement hardcoded. The view now adds itself as a listener for button
configuration changes on linux. For other systems it falls back on a
default set that matches the current (minimize, maximize, close) order.

The layout of the buttons has changed to consult this order definition.

Loading the assets for the close button has been moved out of layout.
ResourceBundle only loads the asset once, so this can be done during
initialization.

The top padding for the buttons has been updated to provide more spacing. It now fits the rest of the padding in the class.

TEST=CustomFrameViewTest
BUG=351917

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269597 0039d316-1c4b-4281-b951-d872f2087c98
parent 7de84840
// Copyright 2014 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 "ui/views/window/window_button_order_provider.h"
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/views/linux_ui/window_button_order_observer.h"
namespace views {
namespace {
class WindowButtonOrderObserverDelegate : public WindowButtonOrderProvider,
public WindowButtonOrderObserver {
public:
WindowButtonOrderObserverDelegate();
virtual ~WindowButtonOrderObserverDelegate();
// WindowButtonOrderObserver:
virtual void OnWindowButtonOrderingChange(
const std::vector<views::FrameButton>& leading_buttons,
const std::vector<views::FrameButton>& trailing_buttons) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(WindowButtonOrderObserverDelegate);
};
///////////////////////////////////////////////////////////////////////////////
// WindowButtonOrderObserverDelegate, public:
WindowButtonOrderObserverDelegate::WindowButtonOrderObserverDelegate() {
views::LinuxUI* ui = views::LinuxUI::instance();
if (ui)
ui->AddWindowButtonOrderObserver(this);
}
WindowButtonOrderObserverDelegate::~WindowButtonOrderObserverDelegate() {
views::LinuxUI* ui = views::LinuxUI::instance();
if (ui)
ui->RemoveWindowButtonOrderObserver(this);
}
void WindowButtonOrderObserverDelegate::OnWindowButtonOrderingChange(
const std::vector<views::FrameButton>& leading_buttons,
const std::vector<views::FrameButton>& trailing_buttons) {
SetWindowButtonOrder(leading_buttons, trailing_buttons);
}
} // namespace
// static
WindowButtonOrderProvider* WindowButtonOrderProvider::instance_ = NULL;
///////////////////////////////////////////////////////////////////////////////
// WindowButtonOrderProvider, public:
// static
WindowButtonOrderProvider* WindowButtonOrderProvider::GetInstance() {
if (!instance_)
instance_ = new WindowButtonOrderObserverDelegate;
return instance_;
}
std::vector<views::FrameButton> const
WindowButtonOrderProvider::GetLeadingButtons() const {
return leading_buttons_;
}
std::vector<views::FrameButton> const
WindowButtonOrderProvider::GetTrailingButtons() const {
return trailing_buttons_;
}
///////////////////////////////////////////////////////////////////////////////
// WindowButtonOrderProvider, protected:
WindowButtonOrderProvider::WindowButtonOrderProvider() {
trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE);
}
WindowButtonOrderProvider::~WindowButtonOrderProvider() {
}
void WindowButtonOrderProvider::SetWindowButtonOrder(
const std::vector<views::FrameButton>& leading_buttons,
const std::vector<views::FrameButton>& trailing_buttons) {
leading_buttons_ = leading_buttons;
trailing_buttons_ = trailing_buttons;
}
} // namespace views
......@@ -287,6 +287,7 @@
'linux_ui/status_icon_linux.h',
'linux_ui/status_icon_linux.cc',
'linux_ui/window_button_order_observer.h',
'linux_ui/window_button_order_provider.cc',
'metrics.cc',
'metrics.h',
'metrics_aura.cc',
......@@ -437,6 +438,8 @@
'window/native_frame_view.h',
'window/non_client_view.cc',
'window/non_client_view.h',
'window/window_button_order_provider.cc',
'window/window_button_order_provider.h',
'window/window_resources.h',
'window/window_shape.cc',
'window/window_shape.h',
......@@ -465,6 +468,9 @@
'dependencies': [
'../shell_dialogs/shell_dialogs.gyp:shell_dialogs',
],
'sources!': [
'window/window_button_order_provider.cc',
],
}, { # OS=="linux" and chromeos==0
'sources/': [
['exclude', 'linux_ui'],
......@@ -665,6 +671,7 @@
'widget/root_view_unittest.cc',
'widget/widget_unittest.cc',
'widget/window_reorderer_unittest.cc',
'window/custom_frame_view_unittest.cc',
'window/dialog_client_view_unittest.cc',
'window/dialog_delegate_unittest.cc',
],
......
......@@ -5,6 +5,7 @@
#include "ui/views/window/custom_frame_view.h"
#include <algorithm>
#include <vector>
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
......@@ -16,6 +17,7 @@
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/path.h"
#include "ui/gfx/rect.h"
#include "ui/views/color_constants.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/views_delegate.h"
......@@ -24,6 +26,7 @@
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/frame_background.h"
#include "ui/views/window/window_button_order_provider.h"
#include "ui/views/window/window_resources.h"
#include "ui/views/window/window_shape.h"
......@@ -67,6 +70,13 @@ const gfx::FontList& GetTitleFontList() {
return title_font_list;
}
void LayoutButton(ImageButton* button, const gfx::Rect& bounds) {
button->SetVisible(true);
button->SetImageAlignment(ImageButton::ALIGN_LEFT,
ImageButton::ALIGN_BOTTOM);
button->SetBoundsRect(bounds);
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
......@@ -80,7 +90,9 @@ CustomFrameView::CustomFrameView()
restore_button_(NULL),
close_button_(NULL),
should_show_maximize_button_(false),
frame_background_(new FrameBackground()) {
frame_background_(new FrameBackground()),
minimum_title_bar_x_(0),
maximum_title_bar_x_(-1) {
}
CustomFrameView::~CustomFrameView() {
......@@ -89,19 +101,12 @@ CustomFrameView::~CustomFrameView() {
void CustomFrameView::Init(Widget* frame) {
frame_ = frame;
close_button_ = new ImageButton(this);
close_button_->SetAccessibleName(
l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
// Close button images will be set in LayoutWindowControls().
AddChildView(close_button_);
close_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_CLOSE,
IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P);
minimize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MINIMIZE,
IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P);
maximize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MAXIMIZE,
IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P);
restore_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_RESTORE,
IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P);
......@@ -276,7 +281,7 @@ int CustomFrameView::NonClientTopBorderHeight() const {
int CustomFrameView::CaptionButtonY() const {
// Maximized buttons start at window top so that even if their images aren't
// drawn flush with the screen edge, they still obey Fitts' Law.
return frame_->IsMaximized() ? FrameBorderThickness() : kFrameShadowThickness;
return frame_->IsMaximized() ? FrameBorderThickness() : kFrameBorderThickness;
}
int CustomFrameView::TitlebarBottomThickness() const {
......@@ -314,7 +319,8 @@ gfx::Rect CustomFrameView::IconBounds() const {
// 3D edge (or nothing at all, for maximized windows) above; hence the +1.
int y = unavailable_px_at_top + (NonClientTopBorderHeight() -
unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size);
return gfx::Rect(frame_thickness + kIconLeftSpacing + minimum_title_bar_x_,
y, size, size);
}
bool CustomFrameView::ShouldShowTitleBarAndBorder() const {
......@@ -468,70 +474,68 @@ const gfx::ImageSkia* CustomFrameView::GetFrameImage() const {
}
void CustomFrameView::LayoutWindowControls() {
close_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
ImageButton::ALIGN_BOTTOM);
minimum_title_bar_x_ = 0;
maximum_title_bar_x_ = width();
if (bounds().IsEmpty())
return;
int caption_y = CaptionButtonY();
bool is_maximized = frame_->IsMaximized();
// There should always be the same number of non-shadow pixels visible to the
// side of the caption buttons. In maximized mode we extend the rightmost
// button to the screen corner to obey Fitts' Law.
int right_extra_width = is_maximized ?
// side of the caption buttons. In maximized mode we extend the edge button
// to the screen corner to obey Fitts' Law.
int extra_width = is_maximized ?
(kFrameBorderThickness - kFrameShadowThickness) : 0;
gfx::Size close_button_size = close_button_->GetPreferredSize();
close_button_->SetBounds(width() - FrameBorderThickness() -
right_extra_width - close_button_size.width(), caption_y,
close_button_size.width() + right_extra_width,
close_button_size.height());
// When the window is restored, we show a maximized button; otherwise, we show
// a restore button.
int next_button_x = FrameBorderThickness();
bool is_restored = !is_maximized && !frame_->IsMinimized();
ImageButton* invisible_button = is_restored ? restore_button_
: maximize_button_;
invisible_button->SetVisible(false);
ImageButton* visible_button = is_restored ? maximize_button_
: restore_button_;
FramePartImage normal_part, hot_part, pushed_part;
int next_button_x;
if (should_show_maximize_button_) {
visible_button->SetVisible(true);
visible_button->SetImageAlignment(ImageButton::ALIGN_LEFT,
ImageButton::ALIGN_BOTTOM);
gfx::Size visible_button_size = visible_button->GetPreferredSize();
visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
caption_y, visible_button_size.width(),
visible_button_size.height());
next_button_x = visible_button->x();
} else {
visible_button->SetVisible(false);
next_button_x = close_button_->x();
WindowButtonOrderProvider* button_order =
WindowButtonOrderProvider::GetInstance();
std::vector<views::FrameButton> leading_buttons =
button_order->GetLeadingButtons();
std::vector<views::FrameButton> trailing_buttons =
button_order->GetTrailingButtons();
ImageButton* button = NULL;
for (std::vector<views::FrameButton>::const_iterator it =
leading_buttons.begin(); it != leading_buttons.end(); ++it) {
button = GetImageButton(*it);
if (!button)
continue;
gfx::Rect target_bounds(gfx::Point(next_button_x, caption_y),
button->GetPreferredSize());
if (it == leading_buttons.begin())
target_bounds.set_width(target_bounds.width() + extra_width);
LayoutButton(button, target_bounds);
next_button_x += button->width();
minimum_title_bar_x_ = std::min(width(), next_button_x);
}
minimize_button_->SetVisible(true);
minimize_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
ImageButton::ALIGN_BOTTOM);
gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
minimize_button_->SetBounds(
next_button_x - minimize_button_size.width(), caption_y,
minimize_button_size.width(),
minimize_button_size.height());
normal_part = IDR_CLOSE;
hot_part = IDR_CLOSE_H;
pushed_part = IDR_CLOSE_P;
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
close_button_->SetImage(CustomButton::STATE_NORMAL,
rb.GetImageNamed(normal_part).ToImageSkia());
close_button_->SetImage(CustomButton::STATE_HOVERED,
rb.GetImageNamed(hot_part).ToImageSkia());
close_button_->SetImage(CustomButton::STATE_PRESSED,
rb.GetImageNamed(pushed_part).ToImageSkia());
// Trailing buttions are laid out in a RTL fashion
next_button_x = width() - FrameBorderThickness();
for (std::vector<views::FrameButton>::const_reverse_iterator it =
trailing_buttons.rbegin(); it != trailing_buttons.rend(); ++it) {
button = GetImageButton(*it);
if (!button)
continue;
gfx::Rect target_bounds(gfx::Point(next_button_x, caption_y),
button->GetPreferredSize());
if (it == trailing_buttons.rbegin())
target_bounds.set_width(target_bounds.width() + extra_width);
target_bounds.Offset(-target_bounds.width(), 0);
LayoutButton(button, target_bounds);
next_button_x = button->x();
maximum_title_bar_x_ = std::max(minimum_title_bar_x_, next_button_x);
}
}
void CustomFrameView::LayoutTitleBar() {
DCHECK_GE(maximum_title_bar_x_, 0);
// The window title position is calculated based on the icon position, even
// when there is no icon.
gfx::Rect icon_bounds(IconBounds());
......@@ -553,7 +557,7 @@ void CustomFrameView::LayoutTitleBar() {
// title from overlapping the 3D edge at the bottom of the titlebar.
title_bounds_.SetRect(title_x,
icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2),
std::max(0, minimize_button_->x() - kTitleCaptionSpacing -
std::max(0, maximum_title_bar_x_ - kTitleCaptionSpacing -
title_x), title_height);
}
......@@ -588,4 +592,31 @@ ImageButton* CustomFrameView::InitWindowCaptionButton(
return button;
}
ImageButton* CustomFrameView::GetImageButton(views::FrameButton frame_button) {
ImageButton* button = NULL;
switch (frame_button) {
case views::FRAME_BUTTON_MINIMIZE: {
button = minimize_button_;
break;
}
case views::FRAME_BUTTON_MAXIMIZE: {
bool is_restored = !frame_->IsMaximized() && !frame_->IsMinimized();
button = is_restored ? maximize_button_ : restore_button_;
if (!should_show_maximize_button_) {
// If we should not show the maximize/restore button, then we return
// NULL as we don't want this button to become visible and to be laid
// out.
button->SetVisible(false);
return NULL;
}
break;
}
case views::FRAME_BUTTON_CLOSE: {
button = close_button_;
break;
}
}
return button;
}
} // namespace views
......@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/window/frame_buttons.h"
#include "ui/views/window/non_client_view.h"
namespace gfx {
......@@ -29,8 +30,8 @@ class Widget;
// rendering the non-standard window caption, border, and controls.
//
////////////////////////////////////////////////////////////////////////////////
class CustomFrameView : public NonClientFrameView,
public ButtonListener {
class VIEWS_EXPORT CustomFrameView : public NonClientFrameView,
public ButtonListener {
public:
CustomFrameView();
virtual ~CustomFrameView();
......@@ -59,6 +60,8 @@ class CustomFrameView : public NonClientFrameView,
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
private:
friend class CustomFrameViewTest;
// Returns the thickness of the border that makes up the window frame edges.
// This does not include any client edge.
int FrameBorderThickness() const;
......@@ -104,8 +107,14 @@ class CustomFrameView : public NonClientFrameView,
SkColor GetFrameColor() const;
const gfx::ImageSkia* GetFrameImage() const;
// Layout various sub-components of this view.
// Performs the layout for the window control buttons based on the
// configuration specified in |leading_buttons_| and |trailing_buttons_|.
// The sizing and positions of the buttons affects LayoutTitleBar, call
// this beforehand.
void LayoutWindowControls();
// Calculations depend on the positions of the window controls. Always call
// LayoutWindowControls beforehand.
void LayoutTitleBar();
void LayoutClientView();
......@@ -116,6 +125,10 @@ class CustomFrameView : public NonClientFrameView,
int hot_image_id,
int pushed_image_id);
// Returns the window caption button for the given FrameButton type, if it
// should be visible. Otherwise NULL.
ImageButton* GetImageButton(views::FrameButton button);
// The bounds of the client view, in this view's coordinates.
gfx::Rect client_view_bounds_;
......@@ -140,6 +153,11 @@ class CustomFrameView : public NonClientFrameView,
// Background painter for the window frame.
scoped_ptr<FrameBackground> frame_background_;
// The horizontal boundaries for the title bar to layout within. Restricted
// by the space used by the leading and trailing buttons.
int minimum_title_bar_x_;
int maximum_title_bar_x_;
DISALLOW_COPY_AND_ASSIGN(CustomFrameView);
};
......
// Copyright 2014 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 "ui/views/window/custom_frame_view.h"
#include <vector>
#include "ui/views/controls/button/image_button.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/window_button_order_provider.h"
namespace views {
namespace {
// Allows for the control of whether or not the widget can maximize or not.
// This can be set after initial setup in order to allow testing of both forms
// of delegates. By default this can maximize.
class MaximizeStateControlDelegate : public WidgetDelegateView {
public:
MaximizeStateControlDelegate() : can_maximize_(true) {}
virtual ~MaximizeStateControlDelegate() {}
void set_can_maximize(bool can_maximize) {
can_maximize_ = can_maximize;
}
// WidgetDelegate:
virtual bool CanMaximize() const OVERRIDE { return can_maximize_; }
private:
bool can_maximize_;
DISALLOW_COPY_AND_ASSIGN(MaximizeStateControlDelegate);
};
} // namespace
class CustomFrameViewTest : public ViewsTestBase {
public:
CustomFrameViewTest() {}
virtual ~CustomFrameViewTest() {}
CustomFrameView* custom_frame_view() {
return custom_frame_view_;
}
MaximizeStateControlDelegate* maximize_state_control_delegate() {
return maximize_state_control_delegate_;
}
Widget* widget() {
return widget_;
}
// ViewsTestBase:
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
protected:
std::vector<views::FrameButton> GetLeadingButtons() {
return WindowButtonOrderProvider::GetInstance()->GetLeadingButtons();
}
std::vector<views::FrameButton> GetTrailingButtons() {
return WindowButtonOrderProvider::GetInstance()->GetTrailingButtons();
}
ImageButton* GetMinimizeButton() {
return custom_frame_view_->minimize_button_;
}
ImageButton* GetMaximizeButton() {
return custom_frame_view_->maximize_button_;
}
ImageButton* GetRestoreButton() {
return custom_frame_view_->restore_button_;
}
ImageButton* GetCloseButton() {
return custom_frame_view_->close_button_;
}
gfx::Rect GetTitleBounds() {
return custom_frame_view_->title_bounds_;
}
void SetWindowButtonOrder(
const std::vector<views::FrameButton> leading_buttons,
const std::vector<views::FrameButton> trailing_buttons);
private:
// Parent container for |custom_frame_view_|
Widget* widget_;
// Owned by |widget_|
CustomFrameView* custom_frame_view_;
// Delegate of |widget_| which controls maximizing
MaximizeStateControlDelegate* maximize_state_control_delegate_;
DISALLOW_COPY_AND_ASSIGN(CustomFrameViewTest);
};
void CustomFrameViewTest::SetUp() {
ViewsTestBase::SetUp();
maximize_state_control_delegate_ = new MaximizeStateControlDelegate;
widget_ = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.delegate = maximize_state_control_delegate_;
params.remove_standard_frame = true;
params.top_level = true;
widget_->Init(params);
custom_frame_view_ = new CustomFrameView;
widget_->non_client_view()->SetFrameView(custom_frame_view_);
}
void CustomFrameViewTest::TearDown() {
widget_->CloseNow();
ViewsTestBase::TearDown();
}
void CustomFrameViewTest::SetWindowButtonOrder(
const std::vector<views::FrameButton> leading_buttons,
const std::vector<views::FrameButton> trailing_buttons) {
WindowButtonOrderProvider::GetInstance()->
SetWindowButtonOrder(leading_buttons, trailing_buttons);
}
// Tests that there is a default button ordering before initialization causes
// a configuration file check.
TEST_F(CustomFrameViewTest, DefaultButtons) {
std::vector<views::FrameButton> trailing = GetTrailingButtons();
EXPECT_EQ(trailing.size(), 3u);
EXPECT_TRUE(GetLeadingButtons().empty());
EXPECT_EQ(trailing[0], FRAME_BUTTON_MINIMIZE);
EXPECT_EQ(trailing[1], FRAME_BUTTON_MAXIMIZE);
EXPECT_EQ(trailing[2], FRAME_BUTTON_CLOSE);
}
// Tests that layout places the buttons in order, that the restore button is
// hidden and the buttons are placed after the title.
TEST_F(CustomFrameViewTest, DefaultButtonLayout) {
Widget* parent = widget();
CustomFrameView* view = custom_frame_view();
view->Init(parent);
parent->SetBounds(gfx::Rect(0, 0, 300, 100));
parent->Show();
EXPECT_LT(GetMinimizeButton()->x(), GetMaximizeButton()->x());
EXPECT_LT(GetMaximizeButton()->x(), GetCloseButton()->x());
EXPECT_FALSE(GetRestoreButton()->visible());
EXPECT_GT(GetMinimizeButton()->x(),
GetTitleBounds().x() + GetTitleBounds().width());
}
// Tests that setting the buttons to leading places them before the title.
TEST_F(CustomFrameViewTest, LeadingButtonLayout) {
Widget* parent = widget();
CustomFrameView* view = custom_frame_view();
std::vector<views::FrameButton> leading;
leading.push_back(views::FRAME_BUTTON_CLOSE);
leading.push_back(views::FRAME_BUTTON_MINIMIZE);
leading.push_back(views::FRAME_BUTTON_MAXIMIZE);
std::vector<views::FrameButton> trailing;
SetWindowButtonOrder(leading, trailing);
view->Init(parent);
parent->SetBounds(gfx::Rect(0, 0, 300, 100));
parent->Show();
EXPECT_LT(GetCloseButton()->x(), GetMinimizeButton()->x());
EXPECT_LT(GetMinimizeButton()->x(), GetMaximizeButton()->x());
EXPECT_FALSE(GetRestoreButton()->visible());
EXPECT_LT(GetMaximizeButton()->x() + GetMaximizeButton()->width(),
GetTitleBounds().x());
}
// Tests that layouts occuring while maximized swap the maximize button for the
// restore button
TEST_F(CustomFrameViewTest, MaximizeRevealsRestoreButton) {
Widget* parent = widget();
CustomFrameView* view = custom_frame_view();
view->Init(parent);
parent->SetBounds(gfx::Rect(0, 0, 300, 100));
parent->Show();
ASSERT_FALSE(GetRestoreButton()->visible());
ASSERT_TRUE(GetMaximizeButton()->visible());
parent->Maximize();
view->Layout();
EXPECT_TRUE(GetRestoreButton()->visible());
EXPECT_FALSE(GetMaximizeButton()->visible());
}
// Tests that when the parent cannot maximize that the maximize button is not
// visible
TEST_F(CustomFrameViewTest, CannotMaximizeHidesButton) {
Widget* parent = widget();
CustomFrameView* view = custom_frame_view();
MaximizeStateControlDelegate* delegate = maximize_state_control_delegate();
delegate->set_can_maximize(false);
view->Init(parent);
parent->SetBounds(gfx::Rect(0, 0, 300, 100));
parent->Show();
EXPECT_FALSE(GetRestoreButton()->visible());
EXPECT_FALSE(GetMaximizeButton()->visible());
}
// Tests that when maximized that the edge button has an increased width.
TEST_F(CustomFrameViewTest, LargerEdgeButtonsWhenMaximized) {
Widget* parent = widget();
CustomFrameView* view = custom_frame_view();
// Custom ordering to have a button on each edge.
std::vector<views::FrameButton> leading;
leading.push_back(views::FRAME_BUTTON_CLOSE);
leading.push_back(views::FRAME_BUTTON_MAXIMIZE);
std::vector<views::FrameButton> trailing;
trailing.push_back(views::FRAME_BUTTON_MINIMIZE);
SetWindowButtonOrder(leading, trailing);
view->Init(parent);
parent->SetBounds(gfx::Rect(0, 0, 300, 100));
parent->Show();
gfx::Rect close_button_initial_bounds = GetCloseButton()->bounds();
gfx::Rect minimize_button_initial_bounds = GetMinimizeButton()->bounds();
parent->Maximize();
view->Layout();
EXPECT_GT(GetCloseButton()->bounds().width(),
close_button_initial_bounds.width());
EXPECT_GT(GetMinimizeButton()->bounds().width(),
minimize_button_initial_bounds.width());
}
} // namespace views
// Copyright 2014 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 "ui/views/window/window_button_order_provider.h"
namespace views {
// static
WindowButtonOrderProvider* WindowButtonOrderProvider::instance_ = NULL;
///////////////////////////////////////////////////////////////////////////////
// WindowButtonOrderProvider, public:
// static
WindowButtonOrderProvider* WindowButtonOrderProvider::GetInstance() {
if (!instance_)
instance_ = new WindowButtonOrderProvider;
return instance_;
}
std::vector<views::FrameButton> const
WindowButtonOrderProvider::GetLeadingButtons() const {
return leading_buttons_;
}
std::vector<views::FrameButton> const
WindowButtonOrderProvider::GetTrailingButtons() const {
return trailing_buttons_;
}
///////////////////////////////////////////////////////////////////////////////
// WindowButtonOrderProvider, protected:
WindowButtonOrderProvider::WindowButtonOrderProvider() {
trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE);
}
WindowButtonOrderProvider::~WindowButtonOrderProvider() {
}
void WindowButtonOrderProvider::SetWindowButtonOrder(
const std::vector<views::FrameButton>& leading_buttons,
const std::vector<views::FrameButton>& trailing_buttons) {
leading_buttons_ = leading_buttons;
trailing_buttons_ = trailing_buttons;
}
} // namespace views
// Copyright 2014 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.
#ifndef UI_VIEWS_WINDOW_WINDOW_BUTTON_ORDER_PROVIDER_H_
#define UI_VIEWS_WINDOW_WINDOW_BUTTON_ORDER_PROVIDER_H_
#include <vector>
#include "base/macros.h"
#include "ui/views/views_export.h"
#include "ui/views/window/frame_buttons.h"
namespace views {
// Stores the ordering of window control buttons. Provides a default ordering
// of |FRAME_BUTTON_MINIMZE|, |FRAME_BUTTON_MAXIMIZE|, |FRAME_BUTTON_CLOSE|,
// where all controls are on the trailing end of a window.
//
// On Linux users can provide configuration files to control the ordering. This
// configuration is checked and overrides the defaults.
class VIEWS_EXPORT WindowButtonOrderProvider {
public:
static WindowButtonOrderProvider* GetInstance();
std::vector<views::FrameButton> const GetLeadingButtons() const;
std::vector<views::FrameButton> const GetTrailingButtons() const;
protected:
WindowButtonOrderProvider();
virtual ~WindowButtonOrderProvider();
void SetWindowButtonOrder(
const std::vector<views::FrameButton>& leading_buttons,
const std::vector<views::FrameButton>& trailing_buttons);
private:
friend class CustomFrameViewTest;
static WindowButtonOrderProvider* instance_;
// Layout arrangement of the window caption buttons. On linux these will be
// set via a WindowButtonOrderObserver. On other platforms a default
// arrangement of a trailing minimize, maximize, close, will be set.
std::vector<views::FrameButton> leading_buttons_;
std::vector<views::FrameButton> trailing_buttons_;
DISALLOW_COPY_AND_ASSIGN(WindowButtonOrderProvider);
};
} // namespace views
#endif // UI_VIEWS_WINDOW_WINDOW_BUTTON_ORDER_PROVIDER_H_
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