Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1928)

Unified Diff: ash/wm/dock/docked_window_layout_manager.cc

Issue 19054013: Implement automatic layout and stacking for docked windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@issue_233331_sized
Patch Set: Implement automatic layout and stacking (separate CL for attached panels and comments) Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ash/wm/dock/docked_window_layout_manager.cc
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc
index c991dc4393c6e44fe48011577c18e36a437d5a86..34b67580a07ed0da2518d84fd369e3334e638961 100644
--- a/ash/wm/dock/docked_window_layout_manager.cc
+++ b/ash/wm/dock/docked_window_layout_manager.cc
@@ -29,6 +29,7 @@ namespace internal {
const int DockedWindowLayoutManager::kMinDockWidth = 200;
const int DockedWindowLayoutManager::kMaxDockWidth = 450;
const int DockedWindowLayoutManager::kMinDockGap = 2;
+const int kWindowIdealSpacing = 4;
namespace {
@@ -49,6 +50,11 @@ bool IsUsedByLayout(aura::Window* window) {
window->type() != aura::client::WINDOW_TYPE_POPUP);
}
+bool CompareWindowPos(const aura::Window* win1, const aura::Window* win2) {
+ return win1->GetTargetBounds().CenterPoint().y() <
+ win2->GetTargetBounds().CenterPoint().y();
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -57,12 +63,14 @@ DockedWindowLayoutManager::DockedWindowLayoutManager(
aura::Window* dock_container)
: dock_container_(dock_container),
in_layout_(false),
+ dragged_former_child_(NULL),
dragged_window_(NULL),
launcher_(NULL),
shelf_layout_manager_(NULL),
shelf_hidden_(false),
docked_width_(0),
- alignment_(DOCKED_ALIGNMENT_NONE) {
+ alignment_(DOCKED_ALIGNMENT_NONE),
+ last_active_(NULL) {
DCHECK(dock_container);
aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
AddObserver(this);
@@ -129,6 +137,13 @@ void DockedWindowLayoutManager::FinishDragging() {
}
dragged_window_ = NULL;
+ // We no longer need |dragged_former_child_| if it is added back;
+ if (dragged_former_child_) {
+ if (dragged_former_child_->parent() != dock_container_)
+ dragged_former_child_->RemoveObserver(this);
+ dragged_former_child_ = NULL;
+ }
+
Relayout();
UpdateDockBounds();
}
@@ -226,7 +241,11 @@ void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
// If this is the first window getting docked - update alignment.
if (alignment_ == DOCKED_ALIGNMENT_NONE)
alignment_ = AlignmentOfWindow(child);
- child->AddObserver(this);
+ // We no longer need |dragged_former_child_| if it is added back.
+ if (child == dragged_former_child_)
+ dragged_former_child_ = NULL;
+ else
+ child->AddObserver(this);
Relayout();
UpdateDockBounds();
}
@@ -248,7 +267,13 @@ void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
if (!found_docked_window)
alignment_ = DOCKED_ALIGNMENT_NONE;
- child->RemoveObserver(this);
+ // Keep track of former children if they are dragged as they can be reparented
+ // temporarily just for the drag.
+ if (child == dragged_window_)
+ dragged_former_child_ = child;
+ else
+ child->RemoveObserver(this);
+
// Close the dock and expand workspace work area.
Relayout();
@@ -326,6 +351,16 @@ void DockedWindowLayoutManager::OnWindowPropertyChanged(aura::Window* window,
RestoreWindow(window);
}
+void DockedWindowLayoutManager::OnWindowBoundsChanged(
+ aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ if (window == dragged_former_child_)
+ Relayout();
+ if (window == dragged_former_child_)
+ LOG(INFO) << "OnWindowBoundsChanged";
+}
+
////////////////////////////////////////////////////////////////////////////////
// DockLayoutManager, aura::client::ActivationChangeObserver implementation:
@@ -408,6 +443,7 @@ void DockedWindowLayoutManager::Relayout() {
gfx::Rect dock_bounds = dock_container_->bounds();
aura::Window* active_window = NULL;
+ aura::Window::Windows visible_windows;
docked_width_ = 0;
for (size_t i = 0; i < dock_container_->children().size(); ++i) {
aura::Window* window(dock_container_->children()[i]);
@@ -423,35 +459,71 @@ void DockedWindowLayoutManager::Relayout() {
window->Hide();
continue;
}
-
if (window->HasFocus() ||
window->Contains(
aura::client::GetFocusClient(window)->GetFocusedWindow())) {
DCHECK(!active_window);
active_window = window;
}
+ visible_windows.push_back(window);
+ }
- // all docked windows other than the one currently dragged remain stuck
- // to the screen edge
+ // Consider windows that were formerly children of the |dock_container_|
+ // when fanning out other child windows.
+ if (dragged_former_child_)
+ visible_windows.push_back(dragged_former_child_);
+
+ // Sort windows by their center positions and fan out overlapping
+ // windows.
+ std::sort(visible_windows.begin(), visible_windows.end(), CompareWindowPos);
+ gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
+ dock_container_);
+ const gfx::Rect work_area = display.work_area();
+ int available_room = work_area.height();
+ for (aura::Window::Windows::const_iterator iter = visible_windows.begin();
+ iter != visible_windows.end(); ++iter) {
+ available_room -= (*iter)->bounds().height();
+ }
+ const int num_windows = visible_windows.size();
+ const int delta = available_room /
+ ((available_room > 0 || num_windows <= 1) ?
+ num_windows + 1 : num_windows - 1);
+ int y_pos = (available_room > 0) ? delta : 0;
+
+ for (aura::Window::Windows::const_iterator iter = visible_windows.begin();
+ iter != visible_windows.end(); ++iter) {
+ aura::Window* window = *iter;
gfx::Rect bounds = window->GetTargetBounds();
- if (window != dragged_window_) {
- switch (alignment_) {
- case DOCKED_ALIGNMENT_LEFT:
- bounds.set_x(0);
- break;
- case DOCKED_ALIGNMENT_RIGHT:
- bounds.set_x(dock_bounds.right() - bounds.width());
- break;
- case DOCKED_ALIGNMENT_NONE:
- NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
- break;
- }
- // Keep the dock at least kMinDockWidth when all windows in it overhang.
- docked_width_ = std::min(kMaxDockWidth,
- std::max(docked_width_,
- bounds.width() > kMaxDockWidth ?
- kMinDockWidth : bounds.width()));
+ // Do not force position of a single window.
+ if (num_windows == 1)
+ y_pos = bounds.y();
+
+ // Fan out windows evenly distributing the overlap or remaining free space.
+ bounds.set_y(std::max(work_area.y(),
+ std::min(work_area.bottom()- bounds.height(),
+ y_pos)));
flackr 2013/07/18 22:16:53 The clamping within the work area should never be
varkha 2013/07/18 22:58:14 I think it may still need clamping in valid corner
+ y_pos += (bounds.height() + delta);
+
+ // All docked windows other than the one currently dragged remain stuck
+ // to the screen edge.
+ if (window == dragged_window_)
+ continue;
+ switch (alignment_) {
+ case DOCKED_ALIGNMENT_LEFT:
+ bounds.set_x(0);
+ break;
+ case DOCKED_ALIGNMENT_RIGHT:
+ bounds.set_x(dock_bounds.right() - bounds.width());
+ break;
+ case DOCKED_ALIGNMENT_NONE:
+ NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
+ break;
}
+ // Keep the dock at least kMinDockWidth when all windows in it overhang.
+ docked_width_ = std::min(kMaxDockWidth,
+ std::max(docked_width_,
+ bounds.width() > kMaxDockWidth ?
+ kMinDockWidth : bounds.width()));
SetChildBoundsDirect(window, bounds);
}
UpdateStacking(active_window);
@@ -475,8 +547,57 @@ void DockedWindowLayoutManager::UpdateDockBounds() {
}
void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
- // TODO(varkha): Implement restacking to ensure that all docked windows are at
- // least partially visible and selectable.
+ if (!active_window) {
+ if (!last_active_)
+ return;
+ active_window = last_active_;
+ }
+
+ // We want to to stack the windows like a deck of cards:
+ // ,------.
+ // |,------.|
+ // |,------.|
+ // | active |
+ // | window |
+ // |`------'|
+ // |`------'|
+ // `------'
+ // We use the middle of each window to figure out how to stack the window.
+ // This allows us to update the stacking when a window is being dragged around
+ // by the titlebar.
+ std::map<int, aura::Window*> window_ordering;
+ for (aura::Window::Windows::const_iterator it =
+ dock_container_->children().begin();
+ it != dock_container_->children().end(); ++it) {
+ gfx::Rect bounds = (*it)->bounds();
+ window_ordering.insert(std::make_pair(bounds.y() + bounds.height() / 2,
+ *it));
+ }
+ int active_center_y = active_window->bounds().CenterPoint().y();
+
+ aura::Window* previous_window = NULL;
+ for (std::map<int, aura::Window*>::const_iterator it =
+ window_ordering.begin();
+ it != window_ordering.end() && it->first < active_center_y; ++it) {
+ if (previous_window)
+ dock_container_->StackChildAbove(it->second, previous_window);
+ previous_window = it->second;
+ }
+
+ previous_window = NULL;
+ for (std::map<int, aura::Window*>::const_reverse_iterator it =
+ window_ordering.rbegin();
+ it != window_ordering.rend() && it->first > active_center_y; ++it) {
+ if (previous_window)
+ dock_container_->StackChildAbove(it->second, previous_window);
+ previous_window = it->second;
+ }
+
+ if (active_window->parent() == dock_container_)
+ dock_container_->StackChildAtTop(active_window);
+ if (dragged_window_ && dragged_window_->parent() == dock_container_)
+ dock_container_->StackChildAtTop(dragged_window_);
+ last_active_ = active_window;
}
////////////////////////////////////////////////////////////////////////////////

Powered by Google App Engine
This is Rietveld 408576698