summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/ash_strings.grd12
-rw-r--r--ash/launcher/launcher.cc43
-rw-r--r--ash/launcher/launcher.h16
-rw-r--r--ash/launcher/launcher_alignment_menu.cc71
-rw-r--r--ash/launcher/launcher_alignment_menu.h43
-rw-r--r--ash/launcher/launcher_button_host.h3
-rw-r--r--ash/launcher/launcher_context_menu.cc6
-rw-r--r--ash/launcher/launcher_context_menu.h4
-rw-r--r--ash/launcher/launcher_types.cc2
-rw-r--r--ash/launcher/launcher_types.h2
-rw-r--r--ash/launcher/launcher_unittest.cc9
-rw-r--r--ash/launcher/launcher_view.cc137
-rw-r--r--ash/launcher/launcher_view.h21
-rw-r--r--ash/launcher/launcher_view_unittest.cc5
-rw-r--r--ash/shell.cc8
-rw-r--r--ash/shell.h3
-rw-r--r--ash/wm/shelf_auto_hide_behavior.h8
-rw-r--r--ash/wm/shelf_layout_manager.cc191
-rw-r--r--ash/wm/shelf_layout_manager.h39
-rw-r--r--ash/wm/shelf_layout_manager_unittest.cc94
-rw-r--r--ash/wm/workspace/workspace_manager.cc6
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/about_flags.cc7
-rw-r--r--chrome/browser/ui/views/ash/launcher/launcher_context_menu.cc11
-rw-r--r--chrome/browser/ui/views/ash/launcher/launcher_context_menu.h7
-rw-r--r--chrome/browser/ui/views/ash/launcher/launcher_favicon_loader.cc4
-rw-r--r--chrome/browser/ui/views/ash/launcher/launcher_favicon_loader_browsertest.cc4
-rw-r--r--chrome/chrome_browser.gypi1
-rw-r--r--chrome/common/chrome_switches.cc5
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--ui/gfx/monitor.cc7
-rw-r--r--ui/gfx/monitor.h3
-rw-r--r--ui/views/view_model_utils.cc38
-rw-r--r--ui/views/view_model_utils.h11
-rw-r--r--ui/views/view_model_utils_unittest.cc49
36 files changed, 691 insertions, 188 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index c622457..abc4eb8 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -72,6 +72,8 @@
'launcher/background_animator.h',
'launcher/launcher.cc',
'launcher/launcher.h',
+ 'launcher/launcher_alignment_menu.cc',
+ 'launcher/launcher_alignment_menu.h',
'launcher/launcher_button.cc',
'launcher/launcher_button.h',
'launcher/launcher_context_menu.cc',
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 4132ff5..cc65e55 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -179,6 +179,18 @@ This file contains the strings for ash.
<message name="IDS_AURA_LAUNCHER_CONTEXT_MENU_AUTO_HIDE_NOT_MAXIMIZED" desc="Title of the menu item in the context menu for auto-hiding the launcher when the current window is not maximized">
Autohide launcher
</message>
+ <message name="IDS_AURA_LAUNCHER_CONTEXT_MENU_POSITION" desc="Title of the menu item in the context menu for aligning the launcher">
+ Launcher position
+ </message>
+ <message name="IDS_AURA_LAUNCHER_CONTEXT_MENU_ALIGN_BOTTOM" desc="Title of the menu item in the context menu for aligning the launcher to the bottom of the screen">
+ Bottom
+ </message>
+ <message name="IDS_AURA_LAUNCHER_CONTEXT_MENU_ALIGN_LEFT" desc="Title of the menu item in the context menu for aligning the launcher to the left of the screen">
+ Left
+ </message>
+ <message name="IDS_AURA_LAUNCHER_CONTEXT_MENU_ALIGN_RIGHT" desc="Title of the menu item in the context menu for aligning the launcher to the right of the screen">
+ Right
+ </message>
<message name="IDS_AURA_SET_DESKTOP_WALLPAPER" desc="The label used for change wallpaper in context menu">
Set wallpaper...
diff --git a/ash/launcher/launcher.cc b/ash/launcher/launcher.cc
index 1376498..aa0024b 100644
--- a/ash/launcher/launcher.cc
+++ b/ash/launcher/launcher.cc
@@ -38,9 +38,6 @@ class Launcher::DelegateView : public views::WidgetDelegate,
explicit DelegateView(Launcher* launcher);
virtual ~DelegateView();
- void SetStatusWidth(int width);
- int status_width() const { return status_width_; }
-
void set_focus_cycler(internal::FocusCycler* focus_cycler) {
focus_cycler_ = focus_cycler;
}
@@ -67,10 +64,6 @@ class Launcher::DelegateView : public views::WidgetDelegate,
private:
Launcher* launcher_;
-
- // Width of the status area.
- int status_width_;
-
internal::FocusCycler* focus_cycler_;
DISALLOW_COPY_AND_ASSIGN(DelegateView);
@@ -78,21 +71,12 @@ class Launcher::DelegateView : public views::WidgetDelegate,
Launcher::DelegateView::DelegateView(Launcher* launcher)
: launcher_(launcher),
- status_width_(0),
focus_cycler_(NULL) {
}
Launcher::DelegateView::~DelegateView() {
}
-void Launcher::DelegateView::SetStatusWidth(int width) {
- if (status_width_ == width)
- return;
-
- status_width_ = width;
- Layout();
-}
-
gfx::Size Launcher::DelegateView::GetPreferredSize() {
return child_count() > 0 ? child_at(0)->GetPreferredSize() : gfx::Size();
}
@@ -100,7 +84,13 @@ gfx::Size Launcher::DelegateView::GetPreferredSize() {
void Launcher::DelegateView::Layout() {
if (child_count() == 0)
return;
- child_at(0)->SetBounds(0, 0, std::max(0, width() - status_width_), height());
+ if (launcher_->alignment_ == SHELF_ALIGNMENT_BOTTOM) {
+ int w = std::max(0, width() - launcher_->status_size_.width());
+ child_at(0)->SetBounds(0, 0, w, height());
+ } else {
+ int h = std::max(0, height() - launcher_->status_size_.height());
+ child_at(0)->SetBounds(0, 0, width(), h);
+ }
}
// Launcher --------------------------------------------------------------------
@@ -110,6 +100,7 @@ Launcher::Launcher(aura::Window* window_container)
window_container_(window_container),
delegate_view_(NULL),
launcher_view_(NULL),
+ alignment_(SHELF_ALIGNMENT_BOTTOM),
ALLOW_THIS_IN_INITIALIZER_LIST(
background_animator_(this, 0, kBackgroundAlpha)) {
model_.reset(new LauncherModel);
@@ -136,7 +127,7 @@ Launcher::Launcher(aura::Window* window_container)
widget_->GetNativeWindow()->SetName("LauncherWindow");
gfx::Size pref =
static_cast<views::View*>(launcher_view_)->GetPreferredSize();
- widget_->SetBounds(gfx::Rect(0, 0, pref.width(), pref.height()));
+ widget_->SetBounds(gfx::Rect(pref));
// The launcher should not take focus when it is initially shown.
widget_->set_focus_on_creation(false);
widget_->SetContentsView(delegate_view_);
@@ -156,18 +147,24 @@ internal::FocusCycler* Launcher::GetFocusCycler() {
return delegate_view_->focus_cycler();
}
+void Launcher::SetAlignment(ShelfAlignment alignment) {
+ alignment_ = alignment;
+ launcher_view_->SetAlignment(alignment);
+ // ShelfLayoutManager will resize the launcher.
+}
+
void Launcher::SetPaintsBackground(
bool value,
internal::BackgroundAnimator::ChangeType change_type) {
background_animator_.SetPaintsBackground(value, change_type);
}
-void Launcher::SetStatusWidth(int width) {
- delegate_view_->SetStatusWidth(width);
-}
+void Launcher::SetStatusSize(const gfx::Size& size) {
+ if (status_size_ == size)
+ return;
-int Launcher::GetStatusWidth() {
- return delegate_view_->status_width();
+ status_size_ = size;
+ delegate_view_->Layout();
}
gfx::Rect Launcher::GetScreenBoundsOfItemIconForWindow(aura::Window* window) {
diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h
index 792d578..9af34bb 100644
--- a/ash/launcher/launcher.h
+++ b/ash/launcher/launcher.h
@@ -9,8 +9,10 @@
#include "ash/ash_export.h"
#include "ash/launcher/background_animator.h"
#include "ash/launcher/launcher_types.h"
+#include "ash/wm/shelf_auto_hide_behavior.h"
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/size.h"
namespace aura {
class Window;
@@ -45,15 +47,18 @@ class ASH_EXPORT Launcher : public internal::BackgroundAnimatorDelegate {
void SetFocusCycler(internal::FocusCycler* focus_cycler);
internal::FocusCycler* GetFocusCycler();
+ void SetAlignment(ShelfAlignment alignment);
+ ShelfAlignment alignment() const { return alignment_; }
+
// Sets whether the launcher paints a background. Default is false, but is set
// to true if a window overlaps the shelf.
void SetPaintsBackground(
bool value,
internal::BackgroundAnimator::ChangeType change_type);
- // Sets the width of the status area.
- void SetStatusWidth(int width);
- int GetStatusWidth();
+ // Sets the size of the status area.
+ void SetStatusSize(const gfx::Size& size);
+ const gfx::Size& status_size() const { return status_size_; }
// Returns the screen bounds of the item for the specified window. If there is
// no item for the specified window an empty rect is returned.
@@ -104,8 +109,13 @@ class ASH_EXPORT Launcher : public internal::BackgroundAnimatorDelegate {
// LauncherView used to display icons.
internal::LauncherView* launcher_view_;
+ ShelfAlignment alignment_;
+
scoped_ptr<LauncherDelegate> delegate_;
+ // Size reserved for the status area.
+ gfx::Size status_size_;
+
// Used to animate the background.
internal::BackgroundAnimator background_animator_;
diff --git a/ash/launcher/launcher_alignment_menu.cc b/ash/launcher/launcher_alignment_menu.cc
new file mode 100644
index 0000000..39226b5
--- /dev/null
+++ b/ash/launcher/launcher_alignment_menu.cc
@@ -0,0 +1,71 @@
+// 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/launcher/launcher_alignment_menu.h"
+
+#include "ash/shell.h"
+#include "ash/wm/shelf_auto_hide_behavior.h"
+#include "grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace ash {
+
+LauncherAlignmentMenu::LauncherAlignmentMenu() : ui::SimpleMenuModel(NULL) {
+ int align_group_id = 1;
+ set_delegate(this);
+ AddRadioItemWithStringId(MENU_ALIGN_LEFT,
+ IDS_AURA_LAUNCHER_CONTEXT_MENU_ALIGN_LEFT,
+ align_group_id);
+ AddRadioItemWithStringId(MENU_ALIGN_BOTTOM,
+ IDS_AURA_LAUNCHER_CONTEXT_MENU_ALIGN_BOTTOM,
+ align_group_id);
+ AddRadioItemWithStringId(MENU_ALIGN_RIGHT,
+ IDS_AURA_LAUNCHER_CONTEXT_MENU_ALIGN_RIGHT,
+ align_group_id);
+}
+
+LauncherAlignmentMenu::~LauncherAlignmentMenu() {
+}
+
+bool LauncherAlignmentMenu::IsCommandIdChecked(int command_id) const {
+ switch (command_id) {
+ case MENU_ALIGN_LEFT:
+ return ash::Shell::GetInstance()->GetShelfAlignment() ==
+ SHELF_ALIGNMENT_LEFT;
+ case MENU_ALIGN_BOTTOM:
+ return ash::Shell::GetInstance()->GetShelfAlignment() ==
+ SHELF_ALIGNMENT_BOTTOM;
+ case MENU_ALIGN_RIGHT:
+ return ash::Shell::GetInstance()->GetShelfAlignment() ==
+ SHELF_ALIGNMENT_RIGHT;
+ default:
+ return false;
+ }
+}
+
+bool LauncherAlignmentMenu::IsCommandIdEnabled(int command_id) const {
+ return true;
+}
+
+bool LauncherAlignmentMenu::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) {
+ return false;
+}
+
+void LauncherAlignmentMenu::ExecuteCommand(int command_id) {
+ switch (static_cast<MenuItem>(command_id)) {
+ case MENU_ALIGN_LEFT:
+ ash::Shell::GetInstance()->SetShelfAlignment(SHELF_ALIGNMENT_LEFT);
+ break;
+ case MENU_ALIGN_BOTTOM:
+ ash::Shell::GetInstance()->SetShelfAlignment(SHELF_ALIGNMENT_BOTTOM);
+ break;
+ case MENU_ALIGN_RIGHT:
+ ash::Shell::GetInstance()->SetShelfAlignment(SHELF_ALIGNMENT_RIGHT);
+ break;
+ }
+}
+
+} // namespace ash
diff --git a/ash/launcher/launcher_alignment_menu.h b/ash/launcher/launcher_alignment_menu.h
new file mode 100644
index 0000000..0c3d23f
--- /dev/null
+++ b/ash/launcher/launcher_alignment_menu.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef ASH_WM_LAUNCHER_LAUNCHER_ALIGNMENT_MENU_H_
+#define ASH_WM_LAUNCHER_LAUNCHER_ALIGNMENT_MENU_H_
+#pragma once
+
+#include "ash/ash_export.h"
+#include "base/basictypes.h"
+#include "ui/base/models/simple_menu_model.h"
+
+namespace ash {
+
+// Submenu for choosing the alignment of the launcher.
+class ASH_EXPORT LauncherAlignmentMenu : public ui::SimpleMenuModel,
+ public ui::SimpleMenuModel::Delegate {
+ public:
+ LauncherAlignmentMenu();
+ virtual ~LauncherAlignmentMenu();
+
+ // ui::SimpleMenuModel::Delegate overrides:
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE;
+ virtual void ExecuteCommand(int command_id) OVERRIDE;
+
+ private:
+ enum MenuItem {
+ // Offset so as not to interfere with other menus.
+ MENU_ALIGN_LEFT = 500,
+ MENU_ALIGN_RIGHT,
+ MENU_ALIGN_BOTTOM,
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(LauncherAlignmentMenu);
+};
+
+} // namespace ash
+
+#endif // ASH_WM_LAUNCHER_LAUNCHER_ALIGNMENT_MENU_H_
diff --git a/ash/launcher/launcher_button_host.h b/ash/launcher/launcher_button_host.h
index 4fbef03..ef8a3be 100644
--- a/ash/launcher/launcher_button_host.h
+++ b/ash/launcher/launcher_button_host.h
@@ -7,6 +7,7 @@
#pragma once
#include "ash/ash_export.h"
+#include "ash/wm/shelf_auto_hide_behavior.h"
#include "base/string16.h"
namespace views {
@@ -36,6 +37,8 @@ class ASH_EXPORT LauncherButtonHost {
// Invoked when the mouse exits the item.
virtual void MouseExitedButton(views::View* view) = 0;
+ virtual ShelfAlignment GetShelfAlignment() const = 0;
+
// Invoked to get the accessible name of the item.
virtual string16 GetAccessibleName(const views::View* view) = 0;
diff --git a/ash/launcher/launcher_context_menu.cc b/ash/launcher/launcher_context_menu.cc
index dd0604e..7b586ba 100644
--- a/ash/launcher/launcher_context_menu.cc
+++ b/ash/launcher/launcher_context_menu.cc
@@ -5,6 +5,7 @@
#include "ash/launcher/launcher_context_menu.h"
#include "ash/shell.h"
+#include "ash/wm/shelf_auto_hide_behavior.h"
#include "grit/ash_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -13,6 +14,9 @@ namespace ash {
LauncherContextMenu::LauncherContextMenu() : ui::SimpleMenuModel(NULL) {
set_delegate(this);
AddCheckItemWithStringId(MENU_AUTO_HIDE, GetAutoHideResourceStringId());
+ AddSubMenuWithStringId(MENU_ALIGNMENT_MENU,
+ IDS_AURA_LAUNCHER_CONTEXT_MENU_POSITION,
+ &alignment_menu_);
}
LauncherContextMenu::~LauncherContextMenu() {
@@ -79,6 +83,8 @@ void LauncherContextMenu::ExecuteCommand(int command_id) {
ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
GetToggledAutoHideBehavior());
break;
+ case MENU_ALIGNMENT_MENU:
+ break;
}
}
diff --git a/ash/launcher/launcher_context_menu.h b/ash/launcher/launcher_context_menu.h
index 0bf706d..768e775 100644
--- a/ash/launcher/launcher_context_menu.h
+++ b/ash/launcher/launcher_context_menu.h
@@ -7,6 +7,7 @@
#pragma once
#include "ash/ash_export.h"
+#include "ash/launcher/launcher_alignment_menu.h"
#include "ash/wm/shelf_auto_hide_behavior.h"
#include "base/basictypes.h"
#include "ui/base/models/simple_menu_model.h"
@@ -40,8 +41,11 @@ class ASH_EXPORT LauncherContextMenu : public ui::SimpleMenuModel,
private:
enum MenuItem {
MENU_AUTO_HIDE,
+ MENU_ALIGNMENT_MENU,
};
+ LauncherAlignmentMenu alignment_menu_;
+
DISALLOW_COPY_AND_ASSIGN(LauncherContextMenu);
};
diff --git a/ash/launcher/launcher_types.cc b/ash/launcher/launcher_types.cc
index bc5b08f..8f04996 100644
--- a/ash/launcher/launcher_types.cc
+++ b/ash/launcher/launcher_types.cc
@@ -6,7 +6,7 @@
namespace ash {
-const int kLauncherPreferredHeight = 48;
+const int kLauncherPreferredSize = 48;
LauncherItem::LauncherItem()
: type(TYPE_TABBED),
diff --git a/ash/launcher/launcher_types.h b/ash/launcher/launcher_types.h
index 0f1bca9..a8b67f8f 100644
--- a/ash/launcher/launcher_types.h
+++ b/ash/launcher/launcher_types.h
@@ -21,7 +21,7 @@ typedef int LauncherID;
// Height of the Launcher. Hard coded to avoid resizing as items are
// added/removed.
-ASH_EXPORT extern const int kLauncherPreferredHeight;
+ASH_EXPORT extern const int kLauncherPreferredSize;
// Type the LauncherItem represents.
enum ASH_EXPORT LauncherItemType {
diff --git a/ash/launcher/launcher_unittest.cc b/ash/launcher/launcher_unittest.cc
index bdb92fc..2a0c1eb 100644
--- a/ash/launcher/launcher_unittest.cc
+++ b/ash/launcher/launcher_unittest.cc
@@ -19,15 +19,16 @@ using ash::internal::LauncherButton;
namespace ash {
-// Makes sure invoking SetStatusWidth on the launcher changes the size of the
+// Makes sure invoking SetStatusSize on the launcher changes the size of the
// LauncherView.
-TEST_F(LauncherTest, SetStatusWidth) {
+TEST_F(LauncherTest, SetStatusSize) {
Launcher* launcher = Shell::GetInstance()->launcher();
LauncherView* launcher_view = launcher->GetLauncherViewForTest();
- int total_width = launcher->widget()->GetWindowScreenBounds().width();
+ gfx::Size launcher_size = launcher->widget()->GetWindowScreenBounds().size();
+ int total_width = launcher_size.width();
ASSERT_GT(total_width, 0);
- launcher->SetStatusWidth(total_width / 2);
+ launcher->SetStatusSize(gfx::Size(total_width / 2, launcher_size.height()));
EXPECT_EQ(total_width - total_width / 2, launcher_view->width());
}
diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc
index 2f2ba3f..1af16ac 100644
--- a/ash/launcher/launcher_view.cc
+++ b/ash/launcher/launcher_view.cc
@@ -45,9 +45,7 @@ static const int kLeadingInset = 8;
// Minimum distance before drag starts.
static const int kMinimumDragDistance = 8;
-// Size given to the buttons on the launcher.
-static const int kButtonWidth = 48;
-static const int kButtonHeight = 48;
+// Size between the buttons.
static const int kButtonSpacing = 4;
namespace {
@@ -250,7 +248,8 @@ LauncherView::LauncherView(LauncherModel* model, LauncherDelegate* delegate)
drag_view_(NULL),
drag_offset_(0),
start_drag_index_(-1),
- context_menu_id_(0) {
+ context_menu_id_(0),
+ alignment_(SHELF_ALIGNMENT_BOTTOM) {
DCHECK(model_);
bounds_animator_.reset(new views::BoundsAnimator(this));
set_context_menu_controller(this);
@@ -293,6 +292,13 @@ void LauncherView::Init() {
// We'll layout when our bounds change.
}
+void LauncherView::SetAlignment(ShelfAlignment alignment) {
+ if (alignment_ == alignment)
+ return;
+ alignment_ = alignment;
+ LayoutToIdealBounds();
+}
+
gfx::Rect LauncherView::GetIdealBoundsOfItemIcon(LauncherID id) {
int index = model_->ItemIndexByID(id);
if (index == -1 || index > last_visible_index_)
@@ -350,23 +356,24 @@ void LauncherView::LayoutToIdealBounds() {
}
void LauncherView::CalculateIdealBounds(IdealBounds* bounds) {
- int available_width = width();
- if (!available_width)
+ int available_size = primary_axis_coordinate(width(), height());
+ if (!available_size)
return;
- int x = kLeadingInset;
+ int x = primary_axis_coordinate(kLeadingInset, 0);
+ int y = primary_axis_coordinate(0, kLeadingInset);
for (int i = 0; i < view_model_->view_size(); ++i) {
- gfx::Size pref(kButtonWidth, kButtonHeight);
view_model_->set_ideal_bounds(i, gfx::Rect(
- x, (kLauncherPreferredHeight - pref.height()) / 2, pref.width(),
- pref.height()));
- x += pref.width() + kButtonSpacing;
+ x, y, kLauncherPreferredSize, kLauncherPreferredSize));
+ x = primary_axis_coordinate(x + kLauncherPreferredSize + kButtonSpacing, 0);
+ y = primary_axis_coordinate(0, y + kLauncherPreferredSize + kButtonSpacing);
}
- bounds->overflow_bounds.set_size(gfx::Size(kButtonWidth, kButtonHeight));
+ bounds->overflow_bounds.set_size(
+ gfx::Size(kLauncherPreferredSize, kLauncherPreferredSize));
last_visible_index_ = DetermineLastVisibleIndex(
- available_width - kLeadingInset - bounds->overflow_bounds.width() -
- kButtonSpacing - kButtonWidth);
+ available_size - kLeadingInset - kLauncherPreferredSize -
+ kButtonSpacing - kLauncherPreferredSize);
int app_list_index = view_model_->view_size() - 1;
bool show_overflow = (last_visible_index_ + 1 < app_list_index);
@@ -378,23 +385,34 @@ void LauncherView::CalculateIdealBounds(IdealBounds* bounds) {
overflow_button_->SetVisible(show_overflow);
if (show_overflow) {
DCHECK_NE(0, view_model_->view_size());
- // We always want the app list visible.
+ if (last_visible_index_ == -1) {
+ x = primary_axis_coordinate(kLeadingInset, 0);
+ y = primary_axis_coordinate(0, kLeadingInset);
+ } else {
+ x = primary_axis_coordinate(
+ view_model_->ideal_bounds(last_visible_index_).right(), 0);
+ y = primary_axis_coordinate(0,
+ view_model_->ideal_bounds(last_visible_index_).bottom());
+ }
gfx::Rect app_list_bounds = view_model_->ideal_bounds(app_list_index);
- x = last_visible_index_ == -1 ?
- kLeadingInset : view_model_->ideal_bounds(last_visible_index_).right();
app_list_bounds.set_x(x);
+ app_list_bounds.set_y(y);
view_model_->set_ideal_bounds(app_list_index, app_list_bounds);
- x = app_list_bounds.right() + kButtonSpacing;
+ x = primary_axis_coordinate(x + kLauncherPreferredSize + kButtonSpacing, 0);
+ y = primary_axis_coordinate(0, y + kLauncherPreferredSize + kButtonSpacing);
bounds->overflow_bounds.set_x(x);
- bounds->overflow_bounds.set_y(
- (kLauncherPreferredHeight - bounds->overflow_bounds.height()) / 2);
+ bounds->overflow_bounds.set_y(y);
}
}
-int LauncherView::DetermineLastVisibleIndex(int max_x) {
+int LauncherView::DetermineLastVisibleIndex(int max_value) {
int index = view_model_->view_size() - 1;
- while (index >= 0 && view_model_->ideal_bounds(index).right() > max_x)
+ while (index >= 0 &&
+ primary_axis_coordinate(
+ view_model_->ideal_bounds(index).right(),
+ view_model_->ideal_bounds(index).bottom()) > max_value) {
index--;
+ }
return index;
}
@@ -511,7 +529,7 @@ void LauncherView::PrepareForDrag(const views::MouseEvent& event) {
void LauncherView::ContinueDrag(const views::MouseEvent& event) {
// TODO: I don't think this works correctly with RTL.
- gfx::Point drag_point(event.x(), 0);
+ gfx::Point drag_point(event.location());
views::View::ConvertPointToView(drag_view_, this, &drag_point);
int current_index = view_model_->GetIndexOfView(drag_view_);
DCHECK_NE(-1, current_index);
@@ -523,28 +541,41 @@ void LauncherView::ContinueDrag(const views::MouseEvent& event) {
return;
}
- // Constrain the x location to the range of valid indices for the type.
+ // Constrain the location to the range of valid indices for the type.
std::pair<int,int> indices(GetDragRange(current_index));
- int x = std::max(view_model_->ideal_bounds(indices.first).x(),
- drag_point.x() - drag_offset_);
- if (view_model_->view_at(indices.second)->visible()) {
- x = std::min(view_model_->ideal_bounds(indices.second).right() -
+ int last_drag_index = indices.second;
+ // If the last index isn't valid, we're overflowing. Constrain to the app list
+ // (which is the last visible item).
+ if (last_drag_index > last_visible_index_)
+ last_drag_index = last_visible_index_;
+ int x = 0, y = 0;
+ if (is_horizontal_alignment()) {
+ x = std::max(view_model_->ideal_bounds(indices.first).x(),
+ drag_point.x() - drag_offset_);
+ x = std::min(view_model_->ideal_bounds(last_drag_index).right() -
view_model_->ideal_bounds(current_index).width(),
x);
+ if (drag_view_->x() == x)
+ return;
+ drag_view_->SetX(x);
} else {
- // If the last index isn't valid, we're overflowing. Constrain to the app
- // list (which is the last visible item).
- x = std::min(
- view_model_->ideal_bounds(view_model_->view_size() - 1).right() -
- view_model_->ideal_bounds(current_index).width(),
- x);
- }
- if (drag_view_->x() == x)
- return;
+ y = std::max(view_model_->ideal_bounds(indices.first).y(),
+ drag_point.y() - drag_offset_);
+ y = std::min(view_model_->ideal_bounds(last_drag_index).bottom() -
+ view_model_->ideal_bounds(current_index).height(),
+ y);
+ if (drag_view_->y() == y)
+ return;
+ drag_view_->SetY(y);
+ }
- drag_view_->SetX(x);
int target_index =
- views::ViewModelUtils::DetermineMoveIndex(*view_model_, drag_view_, x);
+ views::ViewModelUtils::DetermineMoveIndex(
+ *view_model_, drag_view_,
+ is_horizontal_alignment() ?
+ views::ViewModelUtils::HORIZONTAL :
+ views::ViewModelUtils::VERTICAL,
+ x, y);
target_index =
std::min(indices.second, std::max(target_index, indices.first));
if (target_index == current_index)
@@ -671,13 +702,22 @@ void LauncherView::CancelDrag(views::View* deleted_view) {
gfx::Size LauncherView::GetPreferredSize() {
IdealBounds ideal_bounds;
CalculateIdealBounds(&ideal_bounds);
+ if (is_horizontal_alignment()) {
+ if (view_model_->view_size() >= 2) {
+ // Should always have two items.
+ return gfx::Size(view_model_->ideal_bounds(1).right() + kLeadingInset,
+ kLauncherPreferredSize);
+ }
+ return gfx::Size(kLauncherPreferredSize * 2 + kLeadingInset * 2,
+ kLauncherPreferredSize);
+ }
if (view_model_->view_size() >= 2) {
// Should always have two items.
- return gfx::Size(view_model_->ideal_bounds(1).right() + kLeadingInset,
- kLauncherPreferredHeight);
+ return gfx::Size(kLauncherPreferredSize,
+ view_model_->ideal_bounds(1).bottom() + kLeadingInset);
}
- return gfx::Size(kButtonWidth * 2 + kLeadingInset * 2,
- kLauncherPreferredHeight);
+ return gfx::Size(kLauncherPreferredSize,
+ kLauncherPreferredSize * 2 + kLeadingInset * 2);
}
void LauncherView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
@@ -808,14 +848,17 @@ void LauncherView::MousePressedOnButton(views::View* view,
return; // View is being deleted or not draggable, ignore request.
drag_view_ = view;
- drag_offset_ = event.x();
+ drag_offset_ = primary_axis_coordinate(event.x(), event.y());
}
void LauncherView::MouseDraggedOnButton(views::View* view,
const views::MouseEvent& event) {
if (!dragging_ && drag_view_ &&
- abs(event.x() - drag_offset_) >= kMinimumDragDistance)
+ primary_axis_coordinate(abs(event.x() - drag_offset_),
+ abs(event.y() - drag_offset_)) >=
+ kMinimumDragDistance) {
PrepareForDrag(event);
+ }
if (dragging_)
ContinueDrag(event);
}
@@ -834,6 +877,10 @@ void LauncherView::MouseReleasedOnButton(views::View* view,
void LauncherView::MouseExitedButton(views::View* view) {
}
+ShelfAlignment LauncherView::GetShelfAlignment() const {
+ return alignment_;
+}
+
string16 LauncherView::GetAccessibleName(const views::View* view) {
if (!delegate_)
return string16();
diff --git a/ash/launcher/launcher_view.h b/ash/launcher/launcher_view.h
index 64b241d..99c73ef 100644
--- a/ash/launcher/launcher_view.h
+++ b/ash/launcher/launcher_view.h
@@ -11,6 +11,7 @@
#include "ash/launcher/launcher_button_host.h"
#include "ash/launcher/launcher_model_observer.h"
+#include "ash/wm/shelf_auto_hide_behavior.h"
#include "base/observer_list.h"
#include "ui/views/context_menu_controller.h"
#include "ui/views/controls/button/button.h"
@@ -51,6 +52,8 @@ class ASH_EXPORT LauncherView : public views::View,
void Init();
+ void SetAlignment(ShelfAlignment alignment);
+
// Returns the ideal bounds of the specified item, or an empty rect if id
// isn't know.
gfx::Rect GetIdealBoundsOfItemIcon(LauncherID id);
@@ -78,6 +81,15 @@ class ASH_EXPORT LauncherView : public views::View,
gfx::Rect overflow_bounds;
};
+ // Used in calculating ideal bounds.
+ int primary_axis_coordinate(int x, int y) const {
+ return is_horizontal_alignment() ? x : y;
+ }
+
+ bool is_horizontal_alignment() const {
+ return alignment_ == SHELF_ALIGNMENT_BOTTOM;
+ }
+
// Sets the bounds of each view to its ideal bounds.
void LayoutToIdealBounds();
@@ -85,9 +97,9 @@ class ASH_EXPORT LauncherView : public views::View,
// item in the model is set in |view_model_|.
void CalculateIdealBounds(IdealBounds* bounds);
- // Returns the index of the last view whose max x-coordinate is less than
- // |max_x|. Returns -1 if nothing fits, or there are no views.
- int DetermineLastVisibleIndex(int max_x);
+ // Returns the index of the last view whose max primary axis coordinate is
+ // less than |max_value|. Returns -1 if nothing fits, or there are no views.
+ int DetermineLastVisibleIndex(int max_value);
// Animates the bounds of each view to its ideal bounds.
void AnimateToIdealBounds();
@@ -144,6 +156,7 @@ class ASH_EXPORT LauncherView : public views::View,
virtual void MouseReleasedOnButton(views::View* view,
bool canceled) OVERRIDE;
virtual void MouseExitedButton(views::View* view) OVERRIDE;
+ virtual ShelfAlignment GetShelfAlignment() const OVERRIDE;
virtual string16 GetAccessibleName(const views::View* view) OVERRIDE;
// Overriden from views::ButtonListener:
@@ -199,6 +212,8 @@ class ASH_EXPORT LauncherView : public views::View,
ObserverList<LauncherIconObserver> observers_;
+ ShelfAlignment alignment_;
+
DISALLOW_COPY_AND_ASSIGN(LauncherView);
};
diff --git a/ash/launcher/launcher_view_unittest.cc b/ash/launcher/launcher_view_unittest.cc
index fa90f97..73c9d86 100644
--- a/ash/launcher/launcher_view_unittest.cc
+++ b/ash/launcher/launcher_view_unittest.cc
@@ -97,9 +97,10 @@ TEST_F(LauncherViewIconObserverTest, AddRemove) {
TEST_F(LauncherViewIconObserverTest, BoundsChanged) {
Launcher* launcher = Shell::GetInstance()->launcher();
- int total_width = launcher->widget()->GetWindowScreenBounds().width();
+ gfx::Size launcher_size = launcher->widget()->GetWindowScreenBounds().size();
+ int total_width = launcher_size.width() / 2;
ASSERT_GT(total_width, 0);
- launcher->SetStatusWidth(total_width / 2);
+ launcher->SetStatusSize(gfx::Size(total_width, launcher_size.height()));
EXPECT_EQ(1, observer()->count());
observer()->Reset();
}
diff --git a/ash/shell.cc b/ash/shell.cc
index 3eea9a4..b9de6a2 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -876,6 +876,14 @@ ShelfAutoHideBehavior Shell::GetShelfAutoHideBehavior() const {
return shelf_->auto_hide_behavior();
}
+void Shell::SetShelfAlignment(ShelfAlignment alignment) {
+ shelf_->SetAlignment(alignment);
+}
+
+ShelfAlignment Shell::GetShelfAlignment() {
+ return shelf_->alignment();
+}
+
int Shell::GetGridSize() const {
return workspace_controller_->workspace_manager()->grid_size();
}
diff --git a/ash/shell.h b/ash/shell.h
index 8ec275b..163dbc7 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -252,6 +252,9 @@ class ASH_EXPORT Shell {
void SetShelfAutoHideBehavior(ShelfAutoHideBehavior behavior);
ShelfAutoHideBehavior GetShelfAutoHideBehavior() const;
+ void SetShelfAlignment(ShelfAlignment alignment);
+ ShelfAlignment GetShelfAlignment();
+
// TODO(sky): don't expose this!
internal::ShelfLayoutManager* shelf() const { return shelf_; }
diff --git a/ash/wm/shelf_auto_hide_behavior.h b/ash/wm/shelf_auto_hide_behavior.h
index 29c35da..85ee9c0 100644
--- a/ash/wm/shelf_auto_hide_behavior.h
+++ b/ash/wm/shelf_auto_hide_behavior.h
@@ -6,8 +6,16 @@
#define ASH_WM_SHELF_AUTO_HIDE_BEHAVIOR_H_
#pragma once
+// TODO(sky): rename this file to shelf_types.
+
namespace ash {
+enum ShelfAlignment {
+ SHELF_ALIGNMENT_BOTTOM,
+ SHELF_ALIGNMENT_LEFT,
+ SHELF_ALIGNMENT_RIGHT,
+};
+
enum ShelfAutoHideBehavior {
// The default; maximized windows trigger an auto-hide.
SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT,
diff --git a/ash/wm/shelf_layout_manager.cc b/ash/wm/shelf_layout_manager.cc
index 0d344fe..7083521 100644
--- a/ash/wm/shelf_layout_manager.cc
+++ b/ash/wm/shelf_layout_manager.cc
@@ -42,7 +42,7 @@ ui::Layer* GetLayer(views::Widget* widget) {
const int ShelfLayoutManager::kWorkspaceAreaBottomInset = 2;
// static
-const int ShelfLayoutManager::kAutoHideHeight = 2;
+const int ShelfLayoutManager::kAutoHideSize = 2;
// Notifies ShelfLayoutManager any time the mouse moves.
class ShelfLayoutManager::AutoHideEventFilter : public aura::EventFilter {
@@ -122,7 +122,7 @@ ShelfLayoutManager::ShelfLayoutManager(views::Widget* status)
: root_window_(Shell::GetInstance()->GetRootWindow()),
in_layout_(false),
auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT),
- shelf_height_(status->GetWindowScreenBounds().height()),
+ alignment_(SHELF_ALIGNMENT_BOTTOM),
launcher_(NULL),
status_(status),
workspace_manager_(NULL),
@@ -148,12 +148,12 @@ bool ShelfLayoutManager::IsVisible() const {
}
gfx::Rect ShelfLayoutManager::GetMaximizedWindowBounds(
- aura::Window* window) const {
+ aura::Window* window) {
// TODO: needs to be multi-mon aware.
gfx::Rect bounds(gfx::Screen::GetMonitorNearestWindow(window).bounds());
if (auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT ||
auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS) {
- bounds.set_height(bounds.height() - kAutoHideHeight);
+ AdjustBoundsBasedOnAlignment(kAutoHideSize, &bounds);
return bounds;
}
// SHELF_AUTO_HIDE_BEHAVIOR_NEVER maximized windows don't get any taller.
@@ -161,13 +161,18 @@ gfx::Rect ShelfLayoutManager::GetMaximizedWindowBounds(
}
gfx::Rect ShelfLayoutManager::GetUnmaximizedWorkAreaBounds(
- aura::Window* window) const {
+ aura::Window* window) {
// TODO: needs to be multi-mon aware.
gfx::Rect bounds(gfx::Screen::GetMonitorNearestWindow(window).bounds());
- if (auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS)
- bounds.set_height(bounds.height() - kAutoHideHeight);
- else
- bounds.set_height(bounds.height() - shelf_height_);
+ int size;
+ if (auto_hide_behavior_ == SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS) {
+ size = kAutoHideSize;
+ } else {
+ int width, height;
+ GetShelfSize(&width, &height);
+ size = std::max(width, height);
+ }
+ AdjustBoundsBasedOnAlignment(size, &bounds);
return bounds;
}
@@ -176,12 +181,40 @@ void ShelfLayoutManager::SetLauncher(Launcher* launcher) {
return;
launcher_ = launcher;
- shelf_height_ =
- std::max(status_->GetWindowScreenBounds().height(),
- launcher_widget()->GetWindowScreenBounds().height());
LayoutShelf();
}
+void ShelfLayoutManager::SetAlignment(ShelfAlignment alignment) {
+ if (alignment_ == alignment)
+ return;
+
+ alignment_ = alignment;
+ if (launcher_)
+ launcher_->SetAlignment(alignment);
+ LayoutShelf();
+}
+
+gfx::Rect ShelfLayoutManager::GetIdealBounds() {
+ // TODO: this is wrong. Figure out what monitor shelf is on and everything
+ // should be based on it.
+ gfx::Rect bounds(
+ gfx::Screen::GetMonitorNearestWindow(status_->GetNativeView()).bounds());
+ int width = 0, height = 0;
+ GetShelfSize(&width, &height);
+ switch (alignment_) {
+ case SHELF_ALIGNMENT_BOTTOM:
+ return gfx::Rect(bounds.x(), bounds.bottom() - height,
+ bounds.width(), height);
+ case SHELF_ALIGNMENT_LEFT:
+ return gfx::Rect(bounds.x(), bounds.y(), width, bounds.height());
+ case SHELF_ALIGNMENT_RIGHT:
+ return gfx::Rect(bounds.right() - width, bounds.bottom() - height, width,
+ height);
+ }
+ NOTREACHED();
+ return gfx::Rect();
+}
+
void ShelfLayoutManager::LayoutShelf() {
AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
StopAnimating();
@@ -191,8 +224,7 @@ void ShelfLayoutManager::LayoutShelf() {
GetLayer(launcher_widget())->SetOpacity(target_bounds.opacity);
launcher_widget()->SetBounds(target_bounds.launcher_bounds);
- launcher_->SetStatusWidth(
- target_bounds.status_bounds.width());
+ launcher_->SetStatusSize(target_bounds.status_bounds.size());
}
GetLayer(status_)->SetOpacity(target_bounds.opacity);
status_->SetBounds(target_bounds.status_bounds);
@@ -352,47 +384,96 @@ void ShelfLayoutManager::StopAnimating() {
GetLayer(status_)->GetAnimator()->StopAnimating();
}
+void ShelfLayoutManager::GetShelfSize(int* width, int* height) {
+ *width = *height = 0;
+ gfx::Rect status_bounds(status_->GetWindowScreenBounds());
+ gfx::Size launcher_size = launcher_ ?
+ launcher_widget()->GetContentsView()->GetPreferredSize() : gfx::Size();
+ if (alignment_ == SHELF_ALIGNMENT_BOTTOM) {
+ *height = std::max(launcher_size.height(), status_bounds.height());
+ } else {
+ // TODO: include status when supports alignment.
+ *width = launcher_size.width();
+ }
+}
+
+void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset,
+ gfx::Rect* bounds) const {
+ switch (alignment_) {
+ case SHELF_ALIGNMENT_BOTTOM:
+ bounds->Inset(gfx::Insets(0, 0, inset, 0));
+ break;
+ case SHELF_ALIGNMENT_LEFT:
+ bounds->Inset(gfx::Insets(0, inset, 0, 0));
+ break;
+ case SHELF_ALIGNMENT_RIGHT:
+ bounds->Inset(gfx::Insets(0, 0, 0, inset));
+ break;
+ }
+}
+
void ShelfLayoutManager::CalculateTargetBounds(
const State& state,
- TargetBounds* target_bounds) const {
+ TargetBounds* target_bounds) {
const gfx::Rect& available_bounds(
status_->GetNativeView()->GetRootWindow()->bounds());
- int y = available_bounds.bottom();
- int shelf_height = 0;
+ gfx::Rect status_bounds(status_->GetWindowScreenBounds());
+ gfx::Size launcher_size = launcher_ ?
+ launcher_widget()->GetContentsView()->GetPreferredSize() : gfx::Size();
+ int shelf_size = 0;
+ int shelf_width = 0, shelf_height = 0;
+ GetShelfSize(&shelf_width, &shelf_height);
if (state.visibility_state == VISIBLE ||
(state.visibility_state == AUTO_HIDE &&
- state.auto_hide_state == AUTO_HIDE_SHOWN))
- shelf_height = shelf_height_;
- else if (state.visibility_state == AUTO_HIDE &&
- state.auto_hide_state == AUTO_HIDE_HIDDEN)
- shelf_height = kAutoHideHeight;
- y -= shelf_height;
- gfx::Rect status_bounds(status_->GetWindowScreenBounds());
- // The status widget should extend to the bottom and right edges.
- target_bounds->status_bounds = gfx::Rect(
- base::i18n::IsRTL() ? available_bounds.x() :
- available_bounds.right() - status_bounds.width(),
- y + shelf_height_ - status_bounds.height(),
- status_bounds.width(), status_bounds.height());
- if (launcher_widget()) {
- gfx::Rect launcher_bounds(launcher_widget()->GetWindowScreenBounds());
- target_bounds->launcher_bounds = gfx::Rect(
- available_bounds.x(),
- y + (shelf_height_ - launcher_bounds.height()) / 2,
- available_bounds.width(),
- launcher_bounds.height());
+ state.auto_hide_state == AUTO_HIDE_SHOWN)) {
+ shelf_size = std::max(shelf_width, shelf_height);
+ } else if (state.visibility_state == AUTO_HIDE &&
+ state.auto_hide_state == AUTO_HIDE_HIDDEN) {
+ shelf_size = kAutoHideSize;
+ }
+ if (alignment_ == SHELF_ALIGNMENT_BOTTOM) {
+ int y = available_bounds.bottom();
+ y -= shelf_size;
+ // The status widget should extend to the bottom and right edges.
+ target_bounds->status_bounds = gfx::Rect(
+ base::i18n::IsRTL() ? available_bounds.x() :
+ available_bounds.right() - status_bounds.width(),
+ y + shelf_height - status_bounds.height(),
+ status_bounds.width(), status_bounds.height());
+ if (launcher_widget()) {
+ target_bounds->launcher_bounds = gfx::Rect(
+ available_bounds.x(),
+ y + (shelf_height - launcher_size.height()) / 2,
+ available_bounds.width(),
+ launcher_size.height());
+ }
+ target_bounds->work_area_insets.Set(
+ 0, 0, GetWorkAreaSize(state, shelf_height), 0);
+ } else {
+ int x = (alignment_ == SHELF_ALIGNMENT_LEFT) ?
+ available_bounds.x() + shelf_size - shelf_width :
+ available_bounds.right() - shelf_size;
+ target_bounds->status_bounds = gfx::Rect(
+ x, available_bounds.bottom() - status_bounds.height(),
+ shelf_width, status_bounds.height());
+ if (launcher_widget()) {
+ target_bounds->launcher_bounds = gfx::Rect(
+ x,
+ available_bounds.y(),
+ launcher_size.width(),
+ available_bounds.height());
+ }
+ if (alignment_ == SHELF_ALIGNMENT_LEFT) {
+ target_bounds->work_area_insets.Set(
+ 0, GetWorkAreaSize(state, shelf_width), 0, 0);
+ } else {
+ target_bounds->work_area_insets.Set(
+ 0, 0, 0, GetWorkAreaSize(state, shelf_width));
+ }
}
-
target_bounds->opacity =
(state.visibility_state == VISIBLE ||
state.visibility_state == AUTO_HIDE) ? 1.0f : 0.0f;
-
- int work_area_bottom = 0;
- if (state.visibility_state == VISIBLE)
- work_area_bottom = shelf_height_;
- else if (state.visibility_state == AUTO_HIDE)
- work_area_bottom = kAutoHideHeight;
- target_bounds->work_area_insets.Set(0, 0, work_area_bottom, 0);
}
void ShelfLayoutManager::UpdateShelfBackground(
@@ -451,7 +532,17 @@ void ShelfLayoutManager::UpdateHitTestBounds() {
if (state_.visibility_state == VISIBLE) {
// Let clicks at the very top of the launcher through so windows can be
// resized with the bottom-right corner and bottom edge.
- insets.Set(kWorkspaceAreaBottomInset, 0, 0, 0);
+ switch (alignment_) {
+ case SHELF_ALIGNMENT_BOTTOM:
+ insets.Set(kWorkspaceAreaBottomInset, 0, 0, 0);
+ break;
+ case SHELF_ALIGNMENT_LEFT:
+ insets.Set(0, 0, 0, kWorkspaceAreaBottomInset);
+ break;
+ case SHELF_ALIGNMENT_RIGHT:
+ insets.Set(0, kWorkspaceAreaBottomInset, 0, 0);
+ break;
+ }
}
if (launcher_widget() && launcher_widget()->GetNativeWindow())
launcher_widget()->GetNativeWindow()->set_hit_test_bounds_override_outer(
@@ -467,5 +558,13 @@ bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) {
(status_ && status_->GetNativeWindow()->Contains(window));
}
+int ShelfLayoutManager::GetWorkAreaSize(const State& state, int size) const {
+ if (state.visibility_state == VISIBLE)
+ return size;
+ if (state.visibility_state == AUTO_HIDE)
+ return kAutoHideSize;
+ return 0;
+}
+
} // namespace internal
} // namespace ash
diff --git a/ash/wm/shelf_layout_manager.h b/ash/wm/shelf_layout_manager.h
index 9f9275d..32b6019 100644
--- a/ash/wm/shelf_layout_manager.h
+++ b/ash/wm/shelf_layout_manager.h
@@ -64,8 +64,8 @@ class ASH_EXPORT ShelfLayoutManager : public aura::LayoutManager,
// the invisible parts of the launcher.
static const int kWorkspaceAreaBottomInset;
- // Height of the shelf when auto-hidden.
- static const int kAutoHideHeight;
+ // Size of the shelf when auto-hidden.
+ static const int kAutoHideSize;
explicit ShelfLayoutManager(views::Widget* status);
virtual ~ShelfLayoutManager();
@@ -76,6 +76,10 @@ class ASH_EXPORT ShelfLayoutManager : public aura::LayoutManager,
return auto_hide_behavior_;
}
+ // Sets the alignment.
+ void SetAlignment(ShelfAlignment alignment);
+ ShelfAlignment alignment() const { return alignment_; }
+
void set_workspace_manager(WorkspaceManager* manager) {
workspace_manager_ = manager;
}
@@ -90,21 +94,21 @@ class ASH_EXPORT ShelfLayoutManager : public aura::LayoutManager,
bool in_layout() const { return in_layout_; }
- // See description above field.
- int shelf_height() const { return shelf_height_; }
-
// Returns whether the shelf and its contents (launcher, status) are visible
// on the screen.
bool IsVisible() const;
// Returns the bounds the specified window should be when maximized.
- gfx::Rect GetMaximizedWindowBounds(aura::Window* window) const;
- gfx::Rect GetUnmaximizedWorkAreaBounds(aura::Window* window) const;
+ gfx::Rect GetMaximizedWindowBounds(aura::Window* window);
+ gfx::Rect GetUnmaximizedWorkAreaBounds(aura::Window* window);
// The launcher is typically created after the layout manager.
void SetLauncher(Launcher* launcher);
Launcher* launcher() { return launcher_; }
+ // Returns the ideal bounds of the shelf assuming it is visible.
+ gfx::Rect GetIdealBounds();
+
// Stops any animations and sets the bounds of the launcher and status
// widgets.
void LayoutShelf();
@@ -176,9 +180,15 @@ class ASH_EXPORT ShelfLayoutManager : public aura::LayoutManager,
// Stops any animations.
void StopAnimating();
+ // Returns the width (if aligned to the side) or height (if aligned to the
+ // bottom).
+ void GetShelfSize(int* width, int* height);
+
+ // Insets |bounds| by |inset| on the edge the shelf is aligned to.
+ void AdjustBoundsBasedOnAlignment(int inset, gfx::Rect* bounds) const;
+
// Calculates the target bounds assuming visibility of |visible|.
- void CalculateTargetBounds(const State& state,
- TargetBounds* target_bounds) const;
+ void CalculateTargetBounds(const State& state, TargetBounds* target_bounds);
// Updates the background of the shelf.
void UpdateShelfBackground(BackgroundAnimator::ChangeType type);
@@ -199,6 +209,12 @@ class ASH_EXPORT ShelfLayoutManager : public aura::LayoutManager,
// Returns true if |window| is a descendant of the shelf.
bool IsShelfWindow(aura::Window* window);
+ int GetWorkAreaSize(const State& state, int size) const;
+
+ int axis_position(int x, int y) const{
+ return alignment_ == SHELF_ALIGNMENT_BOTTOM ? y : x;
+ }
+
// The RootWindow is cached so that we don't invoke Shell::GetInstance() from
// our destructor. We avoid that as at the time we're deleted Shell is being
// deleted too.
@@ -211,12 +227,11 @@ class ASH_EXPORT ShelfLayoutManager : public aura::LayoutManager,
// See description above setter.
ShelfAutoHideBehavior auto_hide_behavior_;
+ ShelfAlignment alignment_;
+
// Current state.
State state_;
- // Height of the shelf (max of launcher and status).
- int shelf_height_;
-
Launcher* launcher_;
views::Widget* status_;
diff --git a/ash/wm/shelf_layout_manager_unittest.cc b/ash/wm/shelf_layout_manager_unittest.cc
index a0d0a76..f59cb73 100644
--- a/ash/wm/shelf_layout_manager_unittest.cc
+++ b/ash/wm/shelf_layout_manager_unittest.cc
@@ -84,13 +84,18 @@ TEST_F(ShelfLayoutManagerTest, MAYBE_SetVisible) {
// Force an initial layout.
shelf->LayoutShelf();
EXPECT_EQ(ShelfLayoutManager::VISIBLE, shelf->visibility_state());
+
+ gfx::Rect status_bounds(shelf->status()->GetWindowScreenBounds());
+ gfx::Rect launcher_bounds(shelf->launcher_widget()->GetWindowScreenBounds());
+ int shelf_height = shelf->GetIdealBounds().height();
+
const aura::MonitorManager* manager =
aura::Env::GetInstance()->monitor_manager();
const gfx::Monitor& monitor =
manager->GetMonitorNearestWindow(Shell::GetRootWindow());
ASSERT_NE(-1, monitor.id());
// Bottom inset should be the max of widget heights.
- EXPECT_EQ(shelf->shelf_height(),
+ EXPECT_EQ(shelf_height,
monitor.bounds().bottom() - monitor.work_area().bottom());
// Hide the shelf.
@@ -114,19 +119,19 @@ TEST_F(ShelfLayoutManagerTest, MAYBE_SetVisible) {
StepWidgetLayerAnimatorToEnd(shelf->launcher_widget());
StepWidgetLayerAnimatorToEnd(shelf->status());
EXPECT_EQ(ShelfLayoutManager::VISIBLE, shelf->visibility_state());
- EXPECT_EQ(shelf->shelf_height(),
+ EXPECT_EQ(shelf_height,
monitor.bounds().bottom() - monitor.work_area().bottom());
// Make sure the bounds of the two widgets changed.
- gfx::Rect launcher_bounds(
- shelf->launcher_widget()->GetNativeView()->bounds());
+ launcher_bounds = shelf->launcher_widget()->GetNativeView()->bounds();
int bottom = gfx::Screen::GetPrimaryMonitor().bounds().bottom() -
- shelf->shelf_height();
+ shelf_height;
EXPECT_EQ(launcher_bounds.y(),
- bottom + (shelf->shelf_height() - launcher_bounds.height()) / 2);
- gfx::Rect status_bounds(shelf->status()->GetNativeView()->bounds());
+ bottom + (shelf->GetIdealBounds().height() -
+ launcher_bounds.height()) / 2);
+ status_bounds = shelf->status()->GetNativeView()->bounds();
EXPECT_EQ(status_bounds.y(),
- bottom + shelf->shelf_height() - status_bounds.height());
+ bottom + shelf_height - status_bounds.height());
}
// Makes sure LayoutShelf invoked while animating cleans things up.
@@ -165,7 +170,7 @@ TEST_F(ShelfLayoutManagerTest, LauncherInitiallySized) {
shelf_layout_manager->status()->GetWindowScreenBounds().width();
// Test only makes sense if the status is > 0, which is better be.
EXPECT_GT(status_width, 0);
- EXPECT_EQ(status_width, launcher->GetStatusWidth());
+ EXPECT_EQ(status_width, launcher->status_size().width());
}
// Makes sure the launcher is sized when the status area changes size.
@@ -176,7 +181,7 @@ TEST_F(ShelfLayoutManagerTest, LauncherUpdatedWhenStatusAreaChangesSize) {
ASSERT_TRUE(shelf_layout_manager);
ASSERT_TRUE(shelf_layout_manager->status());
shelf_layout_manager->status()->SetBounds(gfx::Rect(0, 0, 200, 200));
- EXPECT_EQ(200, launcher->GetStatusWidth());
+ EXPECT_EQ(200, launcher->status_size().width());
}
// Verifies when the shell is deleted with a full screen window we don't
@@ -210,9 +215,9 @@ TEST_F(ShelfLayoutManagerTest, AutoHide) {
// LayoutShelf() forces the animation to completion, at which point the
// launcher should go off the screen.
shelf->LayoutShelf();
- EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
shelf->launcher_widget()->GetWindowScreenBounds().y());
- EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
gfx::Screen::GetMonitorNearestWindow(root).work_area().bottom());
// Move the mouse to the bottom of the screen.
@@ -222,9 +227,9 @@ TEST_F(ShelfLayoutManagerTest, AutoHide) {
SetState(shelf, ShelfLayoutManager::AUTO_HIDE);
EXPECT_EQ(ShelfLayoutManager::AUTO_HIDE_SHOWN, shelf->auto_hide_state());
shelf->LayoutShelf();
- EXPECT_EQ(root->bounds().bottom() - shelf->shelf_height(),
+ EXPECT_EQ(root->bounds().bottom() - shelf->GetIdealBounds().height(),
shelf->launcher_widget()->GetWindowScreenBounds().y());
- EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
gfx::Screen::GetMonitorNearestWindow(root).work_area().bottom());
// Move mouse back up.
@@ -232,7 +237,7 @@ TEST_F(ShelfLayoutManagerTest, AutoHide) {
SetState(shelf, ShelfLayoutManager::AUTO_HIDE);
EXPECT_EQ(ShelfLayoutManager::AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
shelf->LayoutShelf();
- EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
shelf->launcher_widget()->GetWindowScreenBounds().y());
// Drag mouse to bottom of screen.
@@ -274,7 +279,7 @@ TEST_F(ShelfLayoutManagerTest, VisibleWhenLockScreenShowing) {
// LayoutShelf() forces the animation to completion, at which point the
// launcher should go off the screen.
shelf->LayoutShelf();
- EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
shelf->launcher_widget()->GetWindowScreenBounds().y());
aura::Window* lock_container = Shell::GetInstance()->GetContainer(
@@ -319,23 +324,23 @@ TEST_F(ShelfLayoutManagerTest, SetAutoHideBehavior) {
aura::Window* window = widget->GetNativeWindow();
gfx::Rect monitor_bounds(
gfx::Screen::GetMonitorNearestWindow(window).bounds());
- EXPECT_EQ(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideSize,
shelf->GetMaximizedWindowBounds(window).bottom());
EXPECT_EQ(ShelfLayoutManager::VISIBLE, shelf->visibility_state());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_EQ(ShelfLayoutManager::AUTO_HIDE, shelf->visibility_state());
- EXPECT_EQ(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideSize,
shelf->GetMaximizedWindowBounds(window).bottom());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_DEFAULT);
EXPECT_EQ(ShelfLayoutManager::VISIBLE, shelf->visibility_state());
- EXPECT_EQ(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_EQ(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideSize,
shelf->GetMaximizedWindowBounds(window).bottom());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
EXPECT_EQ(ShelfLayoutManager::VISIBLE, shelf->visibility_state());
- EXPECT_GT(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideHeight,
+ EXPECT_GT(monitor_bounds.bottom() - ShelfLayoutManager::kAutoHideSize,
shelf->GetMaximizedWindowBounds(window).bottom());
widget->Maximize();
@@ -482,5 +487,54 @@ TEST_F(ShelfLayoutManagerTest, DISABLED_OpenAppListWithShelfHiddenState) {
EXPECT_EQ(ShelfLayoutManager::HIDDEN, shelf->visibility_state());
}
+// Tests SHELF_ALIGNMENT_LEFT and SHELF_ALIGNMENT_RIGHT.
+TEST_F(ShelfLayoutManagerTest, SetAlignment) {
+ ShelfLayoutManager* shelf = GetShelfLayoutManager();
+ // Force an initial layout.
+ shelf->LayoutShelf();
+ EXPECT_EQ(ShelfLayoutManager::VISIBLE, shelf->visibility_state());
+
+ shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
+
+ gfx::Rect launcher_bounds(shelf->launcher_widget()->GetWindowScreenBounds());
+ const aura::MonitorManager* manager =
+ aura::Env::GetInstance()->monitor_manager();
+ gfx::Monitor monitor =
+ manager->GetMonitorNearestWindow(Shell::GetRootWindow());
+ ASSERT_NE(-1, monitor.id());
+ EXPECT_EQ(shelf->GetIdealBounds().width(),
+ monitor.GetWorkAreaInsets().left());
+ EXPECT_GE(
+ launcher_bounds.width(),
+ shelf->launcher_widget()->GetContentsView()->GetPreferredSize().width());
+ EXPECT_EQ(shelf->GetIdealBounds().width(),
+ monitor.GetWorkAreaInsets().left());
+ EXPECT_EQ(0, monitor.GetWorkAreaInsets().top());
+ EXPECT_EQ(0, monitor.GetWorkAreaInsets().bottom());
+ EXPECT_EQ(0, monitor.GetWorkAreaInsets().right());
+ EXPECT_EQ(monitor.bounds().x(), launcher_bounds.x());
+ EXPECT_EQ(monitor.bounds().y(), launcher_bounds.y());
+ EXPECT_EQ(monitor.bounds().height(), launcher_bounds.height());
+
+
+ shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
+ launcher_bounds = shelf->launcher_widget()->GetWindowScreenBounds();
+ monitor = manager->GetMonitorNearestWindow(Shell::GetRootWindow());
+ ASSERT_NE(-1, monitor.id());
+ EXPECT_EQ(shelf->GetIdealBounds().width(),
+ monitor.GetWorkAreaInsets().right());
+ EXPECT_GE(
+ launcher_bounds.width(),
+ shelf->launcher_widget()->GetContentsView()->GetPreferredSize().width());
+ EXPECT_EQ(shelf->GetIdealBounds().width(),
+ monitor.GetWorkAreaInsets().right());
+ EXPECT_EQ(0, monitor.GetWorkAreaInsets().top());
+ EXPECT_EQ(0, monitor.GetWorkAreaInsets().bottom());
+ EXPECT_EQ(0, monitor.GetWorkAreaInsets().left());
+ EXPECT_EQ(monitor.work_area().right(), launcher_bounds.x());
+ EXPECT_EQ(monitor.bounds().y(), launcher_bounds.y());
+ EXPECT_EQ(monitor.bounds().height(), launcher_bounds.height());
+}
+
} // namespace internal
} // namespace ash
diff --git a/ash/wm/workspace/workspace_manager.cc b/ash/wm/workspace/workspace_manager.cc
index 6a61b92..d4eda81d 100644
--- a/ash/wm/workspace/workspace_manager.cc
+++ b/ash/wm/workspace/workspace_manager.cc
@@ -137,9 +137,7 @@ WorkspaceManager::WindowState WorkspaceManager::GetWindowState() {
return WINDOW_STATE_DEFAULT;
// TODO: this code needs to be made multi-monitor aware.
- gfx::Rect bounds(
- gfx::Screen::GetMonitorNearestWindow(contents_view_).bounds());
- bounds.set_height(bounds.height() - shelf_->shelf_height());
+ gfx::Rect shelf_bounds(shelf_->GetIdealBounds());
const aura::Window::Windows& windows(contents_view_->children());
bool window_overlaps_launcher = false;
bool has_maximized_window = false;
@@ -155,7 +153,7 @@ WorkspaceManager::WindowState WorkspaceManager::GetWindowState() {
} else if (wm::IsWindowFullscreen(*i)) {
return WINDOW_STATE_FULL_SCREEN;
}
- if (!window_overlaps_launcher && (*i)->bounds().bottom() > bounds.bottom())
+ if (!window_overlaps_launcher && (*i)->bounds().Intersects(shelf_bounds))
window_overlaps_launcher = true;
}
if (has_maximized_window)
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e525e1f..3285cb9 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5606,6 +5606,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_FLAGS_NO_DISCARD_TABS_DESCRIPTION" desc="Description for the flag to disable the tab discarding feature.">
Turns off tab discarding, a feature that discards infrequently used tabs under low memory conditions.
</message>
+ <message name="IDS_FLAGS_SHOW_LAUNCHER_ALIGNMENT_MENU_NAME" desc="Name for the flag to show a menu that lets you change the alignment of the launcher.">
+ Show launcher alignment menu.
+ </message>
+ <message name="IDS_FLAGS_SHOW_LAUNCHER_ALIGNMENT_MENU_DESCRIPTION" desc="Description for the flag to show a menu that lets you change the alignment of the launcher.">
+ Enables a menu that allows changing the side the launcher is aligned to.
+ </message>
<message name="IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME" desc="Name for the NaCl Socket API feature.">
NaCl Socket API.
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 428c81d..895885b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -699,6 +699,13 @@ const Experiment kExperiments[] = {
kOsAll,
SINGLE_VALUE_TYPE(ash::switches::kEnableAppListV2),
},
+ {
+ "show-launcher-alignment-menu",
+ IDS_FLAGS_SHOW_LAUNCHER_ALIGNMENT_MENU_NAME,
+ IDS_FLAGS_SHOW_LAUNCHER_ALIGNMENT_MENU_DESCRIPTION,
+ kOsAll,
+ SINGLE_VALUE_TYPE(switches::kShowLauncherAlignmentMenu)
+ },
#endif
};
diff --git a/chrome/browser/ui/views/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/views/ash/launcher/launcher_context_menu.cc
index b28c7f21..2d655cc 100644
--- a/chrome/browser/ui/views/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/views/ash/launcher/launcher_context_menu.cc
@@ -6,8 +6,11 @@
#include "ash/launcher/launcher_context_menu.h"
#include "ash/shell.h"
+#include "base/command_line.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/common/chrome_switches.h"
+#include "grit/ash_strings.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
@@ -57,6 +60,12 @@ LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller,
}
AddCheckItemWithStringId(
MENU_AUTO_HIDE, ash::LauncherContextMenu::GetAutoHideResourceStringId());
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kShowLauncherAlignmentMenu)) {
+ AddSubMenuWithStringId(MENU_ALIGNMENT_MENU,
+ IDS_AURA_LAUNCHER_CONTEXT_MENU_POSITION,
+ &alignment_menu_);
+ }
}
LauncherContextMenu::~LauncherContextMenu() {
@@ -131,5 +140,7 @@ void LauncherContextMenu::ExecuteCommand(int command_id) {
case MENU_NEW_INCOGNITO_WINDOW:
controller_->CreateNewIncognitoWindow();
break;
+ case MENU_ALIGNMENT_MENU:
+ break;
}
}
diff --git a/chrome/browser/ui/views/ash/launcher/launcher_context_menu.h b/chrome/browser/ui/views/ash/launcher/launcher_context_menu.h
index f02e1db..0cb1395 100644
--- a/chrome/browser/ui/views/ash/launcher/launcher_context_menu.h
+++ b/chrome/browser/ui/views/ash/launcher/launcher_context_menu.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_VIEWS_ASH_LAUNCHER_LAUNCHER_CONTEXT_MENU_H_
#pragma once
+#include "ash/launcher/launcher_alignment_menu.h"
#include "ash/launcher/launcher_types.h"
#include "base/basictypes.h"
#include "ui/base/models/simple_menu_model.h"
@@ -44,7 +45,8 @@ class LauncherContextMenu : public ui::SimpleMenuModel,
LAUNCH_TYPE_WINDOW,
MENU_AUTO_HIDE,
MENU_NEW_WINDOW,
- MENU_NEW_INCOGNITO_WINDOW
+ MENU_NEW_INCOGNITO_WINDOW,
+ MENU_ALIGNMENT_MENU,
};
// Does |item_| represent a valid item? See description of constructor for
@@ -52,8 +54,11 @@ class LauncherContextMenu : public ui::SimpleMenuModel,
bool is_valid_item() const { return item_.id != 0; }
ChromeLauncherController* controller_;
+
ash::LauncherItem item_;
+ ash::LauncherAlignmentMenu alignment_menu_;
+
DISALLOW_COPY_AND_ASSIGN(LauncherContextMenu);
};
diff --git a/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader.cc b/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader.cc
index 8e63fa3..f15884e 100644
--- a/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader.cc
+++ b/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader.cc
@@ -20,7 +20,7 @@ const int kMaxBitmapSize = 256;
////////////////////////////////////////////////////////////////////////////////
// FaviconBitmapHandler fetchs all bitmaps with the 'icon' (or 'shortcut icon')
-// link tag, storing the one that best matches ash::kLauncherPreferredHeight.
+// link tag, storing the one that best matches ash::kLauncherPreferredSize.
// These icon bitmaps are not resized and are not cached beyond the lifetime
// of the class. Bitmaps larger than kMaxBitmapSize are ignored.
@@ -135,7 +135,7 @@ void FaviconBitmapHandler::AddFavicon(const GURL& image_url,
if (new_bitmap.height() > kMaxBitmapSize ||
new_bitmap.width() > kMaxBitmapSize)
return;
- if (new_bitmap.height() < ash::kLauncherPreferredHeight)
+ if (new_bitmap.height() < ash::kLauncherPreferredSize)
return;
if (!bitmap_.isNull()) {
// We want the smallest icon that is large enough.
diff --git a/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader_browsertest.cc b/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader_browsertest.cc
index 9558ccd..83b8615 100644
--- a/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader_browsertest.cc
+++ b/chrome/browser/ui/views/ash/launcher/launcher_favicon_loader_browsertest.cc
@@ -166,8 +166,8 @@ IN_PROC_BROWSER_TEST_F(LauncherFaviconLoaderBrowsertest, ManyLauncherIcons) {
EXPECT_TRUE(WaitForFaviconDownlads(3));
EXPECT_FALSE(favicon_loader->GetFavicon().empty());
// When multiple favicons are present, the correctly sized icon should be
- // chosen. The icons are sized assuming ash::kLauncherPreferredHeight < 128.
- EXPECT_GT(128, ash::kLauncherPreferredHeight);
+ // chosen. The icons are sized assuming ash::kLauncherPreferredSize < 128.
+ EXPECT_GT(128, ash::kLauncherPreferredSize);
EXPECT_EQ(48, favicon_loader->GetFavicon().height());
}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index aa78019..bdad54c 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -4271,6 +4271,7 @@
['use_ash==1', {
'dependencies': [
'../ash/ash.gyp:ash',
+ '../ash/ash_strings.gyp:ash_strings',
'../ui/app_list/app_list.gyp:app_list',
],
}],
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index fd7c1bc..5fa30f2 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1121,6 +1121,9 @@ const char kShowComponentExtensionOptions[] =
// See kHideIcons.
const char kShowIcons[] = "show-icons";
+// If true the alignment of the launcher can be changed.
+const char kShowLauncherAlignmentMenu[] = "show-launcher-alignment-menu";
+
// Changes the DCHECKS to dump memory and continue instead of displaying error
// dialog. This is valid only in Release mode when --enable-dcheck is
// specified.
@@ -1313,7 +1316,7 @@ const char kGuestSession[] = "bwsi";
// Enables overriding the path for the default echo component extension.
// Useful for testing.
-const char kEchoExtensionPath[] = "echo-ext-path";
+const char kEchoExtensionPath[] = "echo-ext-path";
// Show volume controls in status bar on ChromeOS.
const char kShowVolumeStatus[] = "show-volume-status";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 8feb839..41d82dc 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -302,6 +302,7 @@ extern const char kSetToken[];
extern const char kShowAutofillTypePredictions[];
extern const char kShowComponentExtensionOptions[];
extern const char kShowIcons[];
+extern const char kShowLauncherAlignmentMenu[];
extern const char kSilentDumpOnDCHECK[];
extern const char kSimulateUpgrade[];
extern const char kSocketReusePolicy[];
diff --git a/ui/gfx/monitor.cc b/ui/gfx/monitor.cc
index 36dde84..12d4dab 100644
--- a/ui/gfx/monitor.cc
+++ b/ui/gfx/monitor.cc
@@ -58,6 +58,13 @@ Monitor::Monitor(int id, const gfx::Rect& bounds)
Monitor::~Monitor() {
}
+Insets Monitor::GetWorkAreaInsets() const {
+ return gfx::Insets(work_area_.y() - bounds_.y(),
+ work_area_.x() - bounds_.x(),
+ bounds_.bottom() - work_area_.bottom(),
+ bounds_.right() - work_area_.right());
+}
+
void Monitor::SetScaleAndBounds(
float device_scale_factor,
const gfx::Rect& bounds_in_pixel) {
diff --git a/ui/gfx/monitor.h b/ui/gfx/monitor.h
index 03d757f..7428771 100644
--- a/ui/gfx/monitor.h
+++ b/ui/gfx/monitor.h
@@ -54,6 +54,9 @@ class UI_EXPORT Monitor {
const Size& size() const { return bounds_.size(); }
const Size& work_area_size() const { return work_area_.size(); }
+ // Returns the work area insets.
+ Insets GetWorkAreaInsets() const;
+
// Sets the device scale factor and monitor bounds in pixel. This
// updates the work are using the same insets between old bounds and
// work area.
diff --git a/ui/views/view_model_utils.cc b/ui/views/view_model_utils.cc
index addeee7..1d33b14 100644
--- a/ui/views/view_model_utils.cc
+++ b/ui/views/view_model_utils.cc
@@ -11,6 +11,17 @@
namespace views {
+namespace {
+
+// Used in calculating ideal bounds.
+int primary_axis_coordinate(ViewModelUtils::Alignment alignment,
+ int x,
+ int y) {
+ return alignment == ViewModelUtils::HORIZONTAL ? x : y;
+}
+
+} // namespace
+
// static
void ViewModelUtils::SetViewBoundsToIdealBounds(const ViewModel& model) {
for (int i = 0; i < model.view_size(); ++i)
@@ -30,12 +41,18 @@ bool ViewModelUtils::IsAtIdealBounds(const ViewModel& model) {
// static
int ViewModelUtils::DetermineMoveIndex(const ViewModel& model,
View* view,
- int x) {
+ Alignment alignment,
+ int x,
+ int y) {
+ int value = primary_axis_coordinate(alignment, x, y);
int current_index = model.GetIndexOfView(view);
DCHECK_NE(-1, current_index);
for (int i = 0; i < current_index; ++i) {
- int mid_x = model.ideal_bounds(i).x() + model.ideal_bounds(i).width() / 2;
- if (x < mid_x)
+ int mid_point = primary_axis_coordinate(
+ alignment,
+ model.ideal_bounds(i).x() + model.ideal_bounds(i).width() / 2,
+ model.ideal_bounds(i).y() + model.ideal_bounds(i).height() / 2);
+ if (value < mid_point)
return i;
}
@@ -44,12 +61,19 @@ int ViewModelUtils::DetermineMoveIndex(const ViewModel& model,
// For indices after the current index ignore the bounds of the view being
// dragged. This keeps the view from bouncing around as moved.
- int delta = model.ideal_bounds(current_index + 1).x() -
- model.ideal_bounds(current_index).x();
+ int delta = primary_axis_coordinate(
+ alignment,
+ model.ideal_bounds(current_index + 1).x() -
+ model.ideal_bounds(current_index).x(),
+ model.ideal_bounds(current_index + 1).y() -
+ model.ideal_bounds(current_index).y());
for (int i = current_index + 1; i < model.view_size(); ++i) {
const gfx::Rect& bounds(model.ideal_bounds(i));
- int mid_x = bounds.x() + bounds.width() / 2 - delta;
- if (x < mid_x)
+ int mid_point = primary_axis_coordinate(
+ alignment,
+ bounds.x() + bounds.width() / 2 - delta,
+ bounds.y() + bounds.height() / 2 - delta);
+ if (value < mid_point)
return i - 1;
}
return model.view_size() - 1;
diff --git a/ui/views/view_model_utils.h b/ui/views/view_model_utils.h
index d7f8bd3..2993aaa 100644
--- a/ui/views/view_model_utils.h
+++ b/ui/views/view_model_utils.h
@@ -16,16 +16,23 @@ class ViewModel;
class VIEWS_EXPORT ViewModelUtils {
public:
+ enum Alignment {
+ HORIZONTAL,
+ VERTICAL
+ };
+
// Sets the bounds of each view to its ideal bounds.
static void SetViewBoundsToIdealBounds(const ViewModel& model);
// Returns true if the Views in |model| are at their ideal bounds.
static bool IsAtIdealBounds(const ViewModel& model);
- // Returns the index to move |view| to based on a x-coordinate of |x|.
+ // Returns the index to move |view| to based on a coordinate of |x| and |y|.
static int DetermineMoveIndex(const ViewModel& model,
View* view,
- int x);
+ Alignment alignment,
+ int x,
+ int y);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ViewModelUtils);
diff --git a/ui/views/view_model_utils_unittest.cc b/ui/views/view_model_utils_unittest.cc
index 289feee..92004b7 100644
--- a/ui/views/view_model_utils_unittest.cc
+++ b/ui/views/view_model_utils_unittest.cc
@@ -32,15 +32,46 @@ TEST(ViewModelUtils, DetermineMoveIndex) {
model.set_ideal_bounds(1, gfx::Rect(10, 0, 1000, 10));
model.set_ideal_bounds(2, gfx::Rect(1010, 0, 2, 10));
- EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v1, -10));
- EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v1, 4));
- EXPECT_EQ(1, ViewModelUtils::DetermineMoveIndex(model, &v1, 506));
- EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v1, 1010));
- EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v1, 2000));
-
- EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v2, -10));
- EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v2, 4));
- EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v2, 12));
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::HORIZONTAL, -10, 0));
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::HORIZONTAL, 4, 0));
+ EXPECT_EQ(1, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::HORIZONTAL, 506, 0));
+ EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::HORIZONTAL, 1010, 0));
+ EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::HORIZONTAL, 2000, 0));
+
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v2, ViewModelUtils::HORIZONTAL, -10, 0));
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v2, ViewModelUtils::HORIZONTAL, 4, 0));
+ EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
+ model, &v2, ViewModelUtils::HORIZONTAL, 12, 0));
+
+ // Try the same when vertical.
+ model.set_ideal_bounds(0, gfx::Rect(0, 0, 10, 10));
+ model.set_ideal_bounds(1, gfx::Rect(0, 10, 10, 1000));
+ model.set_ideal_bounds(2, gfx::Rect(0, 1010, 10, 2));
+
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::VERTICAL, 0, -10));
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::VERTICAL, 0, 4));
+ EXPECT_EQ(1, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::VERTICAL, 0, 506));
+ EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::VERTICAL, 0, 1010));
+ EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
+ model, &v1, ViewModelUtils::VERTICAL, 0, 2000));
+
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v2, ViewModelUtils::VERTICAL, 0, -10));
+ EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
+ model, &v2, ViewModelUtils::VERTICAL, 0, 4));
+ EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
+ model, &v2, ViewModelUtils::VERTICAL, 0, 12));
}
} // namespace views