stacked_panel_collection.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/panels/stacked_panel_collection.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/auto_reset.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/utf_string_conversions.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/panels/detached_panel_collection.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/panels/display_settings_provider.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/panels/native_panel_stack_window.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/panels/panel.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/panels/panel_constants.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/panels/panel_manager.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/extension.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StackedPanelCollection::StackedPanelCollection(PanelManager* panel_manager)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : PanelCollection(PanelCollection::STACKED),
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      panel_manager_(panel_manager),
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      primary_stack_window_(NULL),
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      secondary_stack_window_(NULL),
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      minimizing_all_(false) {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StackedPanelCollection::~StackedPanelCollection() {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(panels_.empty());
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(most_recently_active_panels_.empty());
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnDisplayChanged() {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.empty())
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect enclosing_bounds = GetEnclosingBounds();
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect work_area = panel_manager_->display_settings_provider()->
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetWorkAreaMatching(enclosing_bounds);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the height of the whole stack is bigger than the height of the new work
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // area, try to reduce the stack height by collapsing panels. In rare case,
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // all panels are collapsed and there is still not enough space. We simply
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // let the stack go beyond the work area limit.
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (enclosing_bounds.height() > work_area.height()) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int needed_space = enclosing_bounds.height() - work_area.height();
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MinimizePanelsForSpace(needed_space);
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect top_bounds = top_panel()->GetBounds();
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int common_width = top_bounds.width();
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (common_width > work_area.width())
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    common_width = work_area.width();
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int common_x = top_bounds.x();
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (common_x + common_width > work_area.right())
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    common_x = work_area.right() - common_width;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (common_x < work_area.x())
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    common_x = work_area.x();
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int total_height = bottom_panel()->GetBounds().bottom() - top_bounds.y();
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int start_y = top_bounds.y();
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (start_y + total_height > work_area.bottom())
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    start_y = work_area.bottom() - total_height;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (start_y < work_area.y())
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    start_y = work_area.y();
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RefreshLayoutWithTopPanelStartingAt(
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      gfx::Point(common_x, start_y), common_width);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::RefreshLayout() {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.empty())
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Rect top_bounds = top_panel()->GetBounds();
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RefreshLayoutWithTopPanelStartingAt(top_bounds.origin(), top_bounds.width());
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StackedPanelCollection::RefreshLayoutWithTopPanelStartingAt(
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const gfx::Point& start_position, int common_width) {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (panels_.empty())
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If only one panel is left in the stack, we only need to check if it should
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // be moved to |start_y| position.
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (panels_.size() == 1) {
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Panel* panel = panels_.front();
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gfx::Rect bounds = panel->GetBounds();
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (bounds.origin() != start_position) {
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bounds.set_origin(start_position);
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      panel->SetPanelBounds(bounds);
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We do not update bounds for affected panels one by one. Instead, all
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // changes are bundled and performed synchronously.
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  primary_stack_window_->BeginBatchUpdatePanelBounds(true);
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (secondary_stack_window_)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    secondary_stack_window_->BeginBatchUpdatePanelBounds(true);
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int y = start_position.y();
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int common_x = start_position.x();
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (Panels::const_iterator iter = panels_.begin();
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       iter != panels_.end(); ++iter) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel = *iter;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The visibility of minimize button might need to be updated due to that
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // top panel might change when a panel is being added or removed from
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the stack.
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    panel->UpdateMinimizeRestoreButtonVisibility();
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Don't update the stacked panel that is in preview mode.
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Rect bounds = panel->GetBounds();
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (panel->in_preview_mode()) {
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      y += bounds.height();
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Update the restored size.
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gfx::Size full_size = panel->full_size();
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    full_size.set_width(common_width);
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    panel->set_full_size(full_size);
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Recompute the bounds.
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bounds.SetRect(
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        common_x,
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        y,
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        common_width,
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        panel->expansion_state() == Panel::EXPANDED ?
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            panel->full_size().height() : panel->TitleOnlyHeight());
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GetStackWindowForPanel(panel)->AddPanelBoundsForBatchUpdate(panel, bounds);
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    y += bounds.height();
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  primary_stack_window_->EndBatchUpdatePanelBounds();
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (secondary_stack_window_)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    secondary_stack_window_->EndBatchUpdatePanelBounds();
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)string16 StackedPanelCollection::GetTitle() const {
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (panels_.empty())
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return string16();
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Panel* panel = panels_.front();
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const extensions::Extension* extension = panel->GetExtension();
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return UTF8ToUTF16(extension && !extension->name().empty() ?
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      extension->name() : panel->app_name());
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StackedPanelCollection::PanelBoundsBatchUpdateCompleted() {
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!secondary_stack_window_ || panels_.empty())
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (top_panel()->in_preview_mode() != bottom_panel()->in_preview_mode() ||
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      primary_stack_window_->IsAnimatingPanelBounds() ||
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      secondary_stack_window_->IsAnimatingPanelBounds())
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Move all panels from secondary stack window to primary stack window.
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  primary_stack_window_->MergeWith(secondary_stack_window_);
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  secondary_stack_window_->Close();
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  secondary_stack_window_ = NULL;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect StackedPanelCollection::GetEnclosingBounds() const {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect enclosing_bounds = top_panel()->GetBounds();
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enclosing_bounds.set_height(
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bottom_panel()->GetBounds().bottom() - enclosing_bounds.y());
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return enclosing_bounds;
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int StackedPanelCollection::MinimizePanelsForSpace(int needed_space) {
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int available_space = GetCurrentAvailableBottomSpace();
176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
177a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Only the most recently active panel might be active.
178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Panel* active_panel = NULL;
179a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!most_recently_active_panels_.empty()) {
180a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    Panel* most_recently_active_panel = most_recently_active_panels_.front();
181a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (most_recently_active_panel->IsActive())
182a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      active_panel = most_recently_active_panel;
183a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
184a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (Panels::const_reverse_iterator iter =
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           most_recently_active_panels_.rbegin();
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != most_recently_active_panels_.rend() &&
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           available_space < needed_space;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       ++iter) {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* current_panel = *iter;
191a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (current_panel != active_panel && !IsPanelMinimized(current_panel)) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      available_space +=
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          current_panel->GetBounds().height() - panel::kTitlebarHeight;
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MinimizePanel(current_panel);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return available_space;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::AddPanel(Panel* panel,
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      PositioningMask positioning_mask) {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(this, panel->collection());
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->set_collection(this);
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panel* adjacent_panel = NULL;
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (positioning_mask & PanelCollection::TOP_POSITION) {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    adjacent_panel = top_panel();
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    panels_.push_front(panel);
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // To fit the new panel within the working area, collapse unfocused panels
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // in the least recent active order until there is enough space.
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (positioning_mask & PanelCollection::COLLAPSE_TO_FIT) {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int needed_space = panel->GetBounds().height();
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int available_space = MinimizePanelsForSpace(needed_space);
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(available_space >= needed_space);
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    adjacent_panel = bottom_panel();
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    panels_.push_back(panel);
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panel->IsActive())
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    most_recently_active_panels_.push_front(panel);
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    most_recently_active_panels_.push_back(panel);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (adjacent_panel)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UpdatePanelCornerStyle(adjacent_panel);
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The secondary stack window should be used when one of the following occurs:
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // 1) Some panels but not all panels are being dragged. This is because
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //    those panels being dragged might not be fully aligned with other panels
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //    not being dragged.
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // 2) The newly added panel is not fully aligned with the existing panel, in
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //    terms of both x and width.
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NativePanelStackWindow* stack_window;
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (top_panel()->in_preview_mode() == bottom_panel()->in_preview_mode() &&
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      top_panel()->GetBounds().x() == bottom_panel()->GetBounds().x() &&
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      top_panel()->GetBounds().width() == bottom_panel()->GetBounds().width()) {
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!primary_stack_window_)
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      primary_stack_window_ = NativePanelStackWindow::Create(this);
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    stack_window = primary_stack_window_;
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!secondary_stack_window_)
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      secondary_stack_window_ = NativePanelStackWindow::Create(this);
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    stack_window = secondary_stack_window_;
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stack_window->AddPanel(panel);
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((positioning_mask & NO_LAYOUT_REFRESH) == 0)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RefreshLayout();
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::RemovePanel(Panel* panel, RemovalReason reason) {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_top = panel == top_panel();
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_bottom = panel == bottom_panel();
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the top panel is being closed, all panels below it should move up. To
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // do this, the top y position of top panel needs to be tracked first.
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool top_panel_closed = false;
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Point top_origin;
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int top_width = 0;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (reason == PanelCollection::PANEL_CLOSED && is_top) {
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    top_panel_closed = true;
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    top_origin = panel->GetBounds().origin();
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    top_width = panel->GetBounds().width();
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->set_collection(NULL);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panels_.remove(panel);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  most_recently_active_panels_.remove(panel);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (is_top) {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* new_top_panel = top_panel();
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (new_top_panel)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdatePanelCornerStyle(new_top_panel);
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (is_bottom) {
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* new_bottom_panel = bottom_panel();
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (new_bottom_panel)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdatePanelCornerStyle(new_bottom_panel);
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If an active panel is being closed, try to focus the next recently active
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // panel in the stack.
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (reason == PanelCollection::PANEL_CLOSED &&
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      panel->IsActive() &&
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !most_recently_active_panels_.empty()) {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    most_recently_active_panels_.front()->Activate();
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If the top panel is closed, move up all other panels to stay at the same
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // y position as the top panel being closed.
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (top_panel_closed)
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RefreshLayoutWithTopPanelStartingAt(top_origin, top_width);
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else if (reason == PanelCollection::PANEL_CLOSED)
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RefreshLayout();
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove the panel from the corresponding stack window.
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetStackWindowForPanel(panel)->RemovePanel(panel);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Close the secondary stack window if no panel is is shown inside it.
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note that we do not need to do this for primary stack window since the
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // whole stack will be gone when only one panel is left.
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (secondary_stack_window_ && secondary_stack_window_->IsEmpty()) {
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    secondary_stack_window_->Close();
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    secondary_stack_window_ = NULL;
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::CloseAll() {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make a copy as closing panels can modify the iterator.
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panels panels_copy = panels_;
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (Panels::const_iterator iter = panels_copy.begin();
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != panels_copy.end(); ++iter)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (*iter)->Close();
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (primary_stack_window_) {
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    primary_stack_window_->Close();
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    primary_stack_window_ = NULL;
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (secondary_stack_window_) {
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    secondary_stack_window_->Close();
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    secondary_stack_window_ = NULL;
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnPanelAttentionStateChanged(Panel* panel) {
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((panel->attention_mode() & Panel::USE_SYSTEM_ATTENTION) != 0)
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    primary_stack_window_->DrawSystemAttention(panel->IsDrawingAttention());
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnPanelTitlebarClicked(
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel, panel::ClickModifier modifier) {
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool expanded = panel->expansion_state() == Panel::EXPANDED;
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (modifier == panel::APPLY_TO_ALL) {
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (expanded)
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MinimizeAll();
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RestoreAll(panel);
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (expanded)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MinimizePanel(panel);
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RestorePanel(panel);
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::ResizePanelWindow(
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel,
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Size& preferred_window_size) {
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::ActivatePanel(Panel* panel) {
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make sure the panel is expanded when activated so the user input
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // does not go into a collapsed window.
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panel->IsMinimized())
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    panel->SetExpansionState(Panel::EXPANDED);
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::MinimizePanel(Panel* panel) {
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->SetExpansionState(Panel::TITLE_ONLY);
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::RestorePanel(Panel* panel) {
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure that the panel could fit within the work area after it is expanded.
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // First, try to collapse the unfocused panel in the least recent active
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // order in order to get enough space.
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int needed_space = panel->full_size().height() - panel->TitleOnlyHeight();
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int available_space = MinimizePanelsForSpace(needed_space);
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is still not enough space, try to move up the stack.
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int space_beyond_available = needed_space - available_space;
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (space_beyond_available > 0) {
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int top_available_space = GetCurrentAvailableTopSpace();
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int move_delta = (space_beyond_available > top_available_space) ?
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        top_available_space : space_beyond_available;
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (Panels::const_iterator iter = panels_.begin();
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         iter != panels_.end(); iter++) {
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Panel* current_panel = *iter;
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Rect bounds = current_panel->GetBounds();
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bounds.set_y(bounds.y() - move_delta);
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      current_panel->SetPanelBounds(bounds);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    available_space += move_delta;
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is still not enough space, shrink the restored height to make it
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // fit at the last resort. Note that the restored height cannot be shrunk less
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // than the minimum panel height. If this is the case, we will just let it
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // expand beyond the screen boundary.
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  space_beyond_available = needed_space - available_space;
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (space_beyond_available > 0) {
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Size full_size = panel->full_size();
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int reduced_height = full_size.height() - space_beyond_available;
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (reduced_height < panel::kPanelMinHeight)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reduced_height = panel::kPanelMinHeight;
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    full_size.set_height(reduced_height);
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    panel->set_full_size(full_size);
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->SetExpansionState(Panel::EXPANDED);
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::MinimizeAll() {
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set minimizing_all_ to prevent deactivation of each panel when it
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is minimized. See comments in OnPanelExpansionStateChanged.
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoReset<bool> pin(&minimizing_all_, true);
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panel* minimized_active_panel = NULL;
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (Panels::const_iterator iter = panels_.begin();
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != panels_.end(); ++iter) {
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ((*iter)->IsActive())
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      minimized_active_panel = *iter;
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MinimizePanel(*iter);
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When a single panel is minimized, it is deactivated to ensure that
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // a minimized panel does not have focus. However, when minimizing all,
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the deactivation is only done once after all panels are minimized,
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // rather than per minimized panel, both for efficiency and to avoid
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // temporary activations of random not-yet-minimized panels.
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (minimized_active_panel) {
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    minimized_active_panel->Deactivate();
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Layout will be refreshed in response to (de)activation notification.
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::RestoreAll(Panel* panel_clicked) {
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Expand the panel being clicked first. This is to make sure at least one
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // panel that is clicked by the user will be expanded.
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RestorePanel(panel_clicked);
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Try to expand all other panels starting from the most recently active
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // panel.
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (Panels::const_iterator iter = most_recently_active_panels_.begin();
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != most_recently_active_panels_.end(); ++iter) {
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If the stack already extends to both top and bottom of the work area,
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // stop now since we cannot fit any more expanded panels.
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (GetCurrentAvailableTopSpace() == 0 &&
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetCurrentAvailableBottomSpace() == 0) {
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel = *iter;
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (panel != panel_clicked)
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RestorePanel(panel);
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnMinimizeButtonClicked(
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel, panel::ClickModifier modifier) {
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The minimize button is only present in the top panel.
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(top_panel(), panel);
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  primary_stack_window_->Minimize();
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnRestoreButtonClicked(
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel, panel::ClickModifier modifier) {
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool StackedPanelCollection::CanShowMinimizeButton(const Panel* panel) const {
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Only the top panel in the stack shows the minimize button.
464a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return PanelManager::CanUseSystemMinimize() && panel == top_panel();
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool StackedPanelCollection::CanShowRestoreButton(const Panel* panel) const {
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool StackedPanelCollection::IsPanelMinimized(const Panel* panel) const {
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return panel->expansion_state() != Panel::EXPANDED;
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::SavePanelPlacement(Panel* panel) {
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!saved_panel_placement_.panel);
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  saved_panel_placement_.panel = panel;
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (top_panel() != panel)
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    saved_panel_placement_.top_panel = top_panel();
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    saved_panel_placement_.position = panel->GetBounds().origin();
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  saved_panel_placement_.top_panel = top_panel() != panel ? top_panel() : NULL;
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::RestorePanelToSavedPlacement() {
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(saved_panel_placement_.panel);
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (saved_panel_placement_.top_panel) {
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Restore the top panel if it has been moved out of the stack. This could
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // happen when there're 2 panels in the stack and the bottom panel is being
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // dragged out of the stack and thus cause both panels become detached.
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (saved_panel_placement_.top_panel->stack() != this) {
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_EQ(PanelCollection::DETACHED,
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                saved_panel_placement_.top_panel->collection()->type());
497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      panel_manager_->MovePanelToCollection(
498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          saved_panel_placement_.top_panel,
499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          this,
500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          static_cast<PanelCollection::PositioningMask>(
501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              PanelCollection::TOP_POSITION |
502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              PanelCollection::NO_LAYOUT_REFRESH));
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RefreshLayout();
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Restore the position when the top panel is being dragged.
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(top_panel(), saved_panel_placement_.panel);
508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RefreshLayoutWithTopPanelStartingAt(saved_panel_placement_.position,
509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        top_panel()->GetBounds().width());
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DiscardSavedPanelPlacement();
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::DiscardSavedPanelPlacement() {
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(saved_panel_placement_.panel);
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  saved_panel_placement_.panel = NULL;
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  saved_panel_placement_.top_panel = NULL;
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)panel::Resizability StackedPanelCollection::GetPanelResizability(
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Panel* panel) const {
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The panel in the stack can be resized by the following rules:
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // * If collapsed, it can only be resized by its left or right edge.
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // * Otherwise, it can be resized by its left or right edge plus:
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   % top edge and corners, if it is at the top;
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   % bottom edge, if it is not at the bottom.
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   % bottom edge and corners, if it is at the bottom.
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel::Resizability resizability = static_cast<panel::Resizability>(
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      panel::RESIZABLE_LEFT | panel::RESIZABLE_RIGHT);
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panel->IsMinimized())
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return resizability;
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panel == top_panel()) {
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resizability = static_cast<panel::Resizability>(resizability |
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        panel::RESIZABLE_TOP | panel::RESIZABLE_TOP_LEFT |
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        panel::RESIZABLE_TOP_RIGHT);
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panel == bottom_panel()) {
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resizability = static_cast<panel::Resizability>(resizability |
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        panel::RESIZABLE_BOTTOM | panel::RESIZABLE_BOTTOM_LEFT |
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        panel::RESIZABLE_BOTTOM_RIGHT);
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resizability = static_cast<panel::Resizability>(resizability |
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        panel::RESIZABLE_BOTTOM);
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return resizability;
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnPanelResizedByMouse(
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* resized_panel, const gfx::Rect& new_bounds) {
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  resized_panel->set_full_size(new_bounds.size());
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!secondary_stack_window_);
554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  primary_stack_window_->BeginBatchUpdatePanelBounds(false);
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The delta x and width can be computed from the difference between
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the panel being resized and any other panel.
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panel* other_panel = resized_panel == top_panel() ? bottom_panel()
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                    : top_panel();
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect other_bounds = other_panel->GetBounds();
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int delta_x = new_bounds.x() - other_bounds.x();
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int delta_width = new_bounds.width() - other_bounds.width();
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect previous_bounds;
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool resized_panel_found = false;
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool panel_below_resized_panel_updated = false;
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (Panels::const_iterator iter = panels_.begin();
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != panels_.end(); iter++) {
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel = *iter;
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (panel == resized_panel) {
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // |new_bounds| should be used since the panel bounds have not been
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // updated yet.
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      previous_bounds = new_bounds;
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resized_panel_found = true;
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      primary_stack_window_->AddPanelBoundsForBatchUpdate(panel, new_bounds);
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gfx::Rect bounds = panel->GetBounds();
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds.set_x(bounds.x() + delta_x);
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds.set_width(bounds.width() + delta_width);
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If the panel below the panel being resized is expanded, update its
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // height to offset the height change of the panel being resized.
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // For example, the stack has P1 and P2 (from top to bottom). P1's height
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // is 100 and P2's height is 120. If P1's bottom increases by 10, P2's
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // height needs to shrink by 10.
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (resized_panel_found) {
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!panel_below_resized_panel_updated && !panel->IsMinimized()) {
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        int old_bottom = bounds.bottom();
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bounds.set_y(previous_bounds.bottom());
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bounds.set_height(old_bottom - bounds.y());
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bounds.set_y(previous_bounds.bottom());
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      panel_below_resized_panel_updated = true;
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!panel->IsMinimized())
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      panel->set_full_size(bounds.size());
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    primary_stack_window_->AddPanelBoundsForBatchUpdate(panel, bounds);
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    previous_bounds = bounds;
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  primary_stack_window_->EndBatchUpdatePanelBounds();
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool StackedPanelCollection::HasPanel(Panel* panel) const {
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return std::find(panels_.begin(), panels_.end(), panel) != panels_.end();
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::UpdatePanelOnCollectionChange(Panel* panel) {
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->set_attention_mode(
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<Panel::AttentionMode>(Panel::USE_PANEL_ATTENTION |
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        Panel::USE_SYSTEM_ATTENTION));
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->SetAlwaysOnTop(false);
618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  panel->ShowShadow(false);
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->EnableResizeByMouse(true);
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->UpdateMinimizeRestoreButtonVisibility();
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdatePanelCornerStyle(panel);
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnPanelExpansionStateChanged(Panel* panel) {
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(Panel::MINIMIZED, panel->expansion_state());
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure minimized panel does not get the focus. If minimizing all,
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the active panel will be deactivated once when all panels are minimized
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // rather than per minimized panel.
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panel->expansion_state() != Panel::EXPANDED && !minimizing_all_ &&
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      panel->IsActive()) {
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    panel->Deactivate();
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The bounds change per expansion state will be done in RefreshLayout.
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RefreshLayout();
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::OnPanelActiveStateChanged(Panel* panel) {
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!panel->IsActive())
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
643a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Move the panel to the front if not yet.
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panels::iterator iter = std::find(most_recently_active_panels_.begin(),
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      most_recently_active_panels_.end(), panel);
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(iter != most_recently_active_panels_.end());
647a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (iter != most_recently_active_panels_.begin()) {
648a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    most_recently_active_panels_.erase(iter);
649a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    most_recently_active_panels_.push_front(panel);
650a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  GetStackWindowForPanel(panel)->OnPanelActivated(panel);
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::Rect StackedPanelCollection::GetInitialPanelBounds(
656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const gfx::Rect& requested_bounds) const {
657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!panels_.empty());
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Rect bottom_panel_bounds = bottom_panel()->GetBounds();
659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return gfx::Rect(bottom_panel_bounds.x(),
660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   bottom_panel_bounds.bottom(),
661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   bottom_panel_bounds.width(),
662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   requested_bounds.height());
663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Panel* StackedPanelCollection::GetPanelAbove(Panel* panel) const {
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(panel);
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.size() < 2)
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panels::const_iterator iter = panels_.begin();
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panel* above_panel = *iter;
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (; iter != panels_.end(); ++iter) {
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (*iter == panel)
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return above_panel;
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    above_panel = *iter;
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Panel* StackedPanelCollection::GetPanelBelow(Panel* panel) const {
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(panel);
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.size() < 2)
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Panels::const_iterator iter =
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::find(panels_.begin(), panels_.end(), panel);
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (iter == panels_.end())
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++iter;
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return iter == panels_.end() ? NULL : *iter;
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::MoveAllDraggingPanelsInstantly(
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Vector2d& delta_origin) {
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (Panels::const_iterator iter = panels_.begin();
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != panels_.end(); iter++) {
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel = *iter;
698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (panel->in_preview_mode()) {
699c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetStackWindowForPanel(panel)->MovePanelsBy(delta_origin);
700c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
701c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool StackedPanelCollection::IsMinimized() const {
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return primary_stack_window_->IsMinimized();
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool StackedPanelCollection::IsAnimatingPanelBounds(Panel* panel) const {
710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return GetStackWindowForPanel(panel)->IsAnimatingPanelBounds();
711c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
712c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StackedPanelCollection::UpdatePanelCornerStyle(Panel* panel) {
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel::CornerStyle corner_style;
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool at_top = panel == top_panel();
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool at_bottom = panel == bottom_panel();
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (at_top && at_bottom)
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    corner_style = panel::ALL_ROUNDED;
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (at_top)
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    corner_style = panel::TOP_ROUNDED;
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (at_bottom)
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    corner_style = panel::BOTTOM_ROUNDED;
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    corner_style = panel::NOT_ROUNDED;
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  panel->SetWindowCornerStyle(corner_style);
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect StackedPanelCollection::GetWorkArea() const {
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.empty())
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return panel_manager_->display_settings_provider()->GetPrimaryWorkArea();
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return panel_manager_->display_settings_provider()->GetWorkAreaMatching(
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetEnclosingBounds());
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int StackedPanelCollection::GetCurrentAvailableTopSpace() const {
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect work_area = GetWorkArea();
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.empty())
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return work_area.height();
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int available_space = top_panel()->GetBounds().y() - work_area.y();
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (available_space < 0)
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    available_space = 0;
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return available_space;
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int StackedPanelCollection::GetCurrentAvailableBottomSpace() const {
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect work_area = GetWorkArea();
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.empty())
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return work_area.height();
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int available_space = work_area.bottom() -
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bottom_panel()->GetBounds().bottom();
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (available_space < 0)
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    available_space = 0;
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return available_space;
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int StackedPanelCollection::GetMaximiumAvailableBottomSpace() const {
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect work_area = GetWorkArea();
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (panels_.empty())
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return work_area.height();
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom = top_panel()->GetBounds().y();
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (Panels::const_iterator iter = panels_.begin();
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != panels_.end(); iter++) {
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Panel* panel = *iter;
767a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // Only the most recently active panel might be active.
768a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (iter == panels_.begin() && panel->IsActive())
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bottom += panel->GetBounds().height();
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bottom += panel::kTitlebarHeight;
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int available_space = work_area.bottom() - bottom;
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (available_space < 0)
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    available_space = 0;
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return available_space;
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
778c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
779c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)NativePanelStackWindow* StackedPanelCollection::GetStackWindowForPanel(
780c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Panel* panel) const {
781c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return secondary_stack_window_ && secondary_stack_window_->HasPanel(panel) ?
782c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      secondary_stack_window_ : primary_stack_window_;
783c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
784