Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / panels / stacked_panel_collection.cc
blob7bcf5081967dca7784e798511f1161b65cb78576
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/panels/stacked_panel_collection.h"
7 #include <algorithm>
8 #include "base/auto_reset.h"
9 #include "base/logging.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/ui/panels/detached_panel_collection.h"
12 #include "chrome/browser/ui/panels/display_settings_provider.h"
13 #include "chrome/browser/ui/panels/native_panel_stack_window.h"
14 #include "chrome/browser/ui/panels/panel.h"
15 #include "chrome/browser/ui/panels/panel_constants.h"
16 #include "chrome/browser/ui/panels/panel_manager.h"
17 #include "extensions/common/extension.h"
19 StackedPanelCollection::StackedPanelCollection(PanelManager* panel_manager)
20 : PanelCollection(PanelCollection::STACKED),
21 panel_manager_(panel_manager),
22 primary_stack_window_(NULL),
23 secondary_stack_window_(NULL),
24 minimizing_all_(false) {
27 StackedPanelCollection::~StackedPanelCollection() {
28 DCHECK(panels_.empty());
29 DCHECK(most_recently_active_panels_.empty());
32 void StackedPanelCollection::OnDisplayChanged() {
33 if (panels_.empty())
34 return;
36 gfx::Rect enclosing_bounds = GetEnclosingBounds();
37 gfx::Rect work_area = panel_manager_->display_settings_provider()->
38 GetWorkAreaMatching(enclosing_bounds);
40 // If the height of the whole stack is bigger than the height of the new work
41 // area, try to reduce the stack height by collapsing panels. In rare case,
42 // all panels are collapsed and there is still not enough space. We simply
43 // let the stack go beyond the work area limit.
44 if (enclosing_bounds.height() > work_area.height()) {
45 int needed_space = enclosing_bounds.height() - work_area.height();
46 MinimizePanelsForSpace(needed_space);
49 gfx::Rect top_bounds = top_panel()->GetBounds();
50 int common_width = top_bounds.width();
51 if (common_width > work_area.width())
52 common_width = work_area.width();
54 int common_x = top_bounds.x();
55 if (common_x + common_width > work_area.right())
56 common_x = work_area.right() - common_width;
57 if (common_x < work_area.x())
58 common_x = work_area.x();
60 int total_height = bottom_panel()->GetBounds().bottom() - top_bounds.y();
61 int start_y = top_bounds.y();
62 if (start_y + total_height > work_area.bottom())
63 start_y = work_area.bottom() - total_height;
64 if (start_y < work_area.y())
65 start_y = work_area.y();
67 RefreshLayoutWithTopPanelStartingAt(
68 gfx::Point(common_x, start_y), common_width);
71 void StackedPanelCollection::RefreshLayout() {
72 if (panels_.empty())
73 return;
74 gfx::Rect top_bounds = top_panel()->GetBounds();
75 RefreshLayoutWithTopPanelStartingAt(top_bounds.origin(), top_bounds.width());
78 void StackedPanelCollection::RefreshLayoutWithTopPanelStartingAt(
79 const gfx::Point& start_position, int common_width) {
80 if (panels_.empty())
81 return;
83 // If only one panel is left in the stack, we only need to check if it should
84 // be moved to |start_y| position.
85 if (panels_.size() == 1) {
86 Panel* panel = panels_.front();
87 gfx::Rect bounds = panel->GetBounds();
88 if (bounds.origin() != start_position) {
89 bounds.set_origin(start_position);
90 panel->SetPanelBounds(bounds);
92 return;
95 // We do not update bounds for affected panels one by one. Instead, all
96 // changes are bundled and performed synchronously.
97 primary_stack_window_->BeginBatchUpdatePanelBounds(true);
98 if (secondary_stack_window_)
99 secondary_stack_window_->BeginBatchUpdatePanelBounds(true);
101 int y = start_position.y();
102 int common_x = start_position.x();
103 for (Panels::const_iterator iter = panels_.begin();
104 iter != panels_.end(); ++iter) {
105 Panel* panel = *iter;
107 // The visibility of minimize button might need to be updated due to that
108 // top panel might change when a panel is being added or removed from
109 // the stack.
110 panel->UpdateMinimizeRestoreButtonVisibility();
112 // Don't update the stacked panel that is in preview mode.
113 gfx::Rect bounds = panel->GetBounds();
114 if (panel->in_preview_mode()) {
115 y += bounds.height();
116 continue;
119 // Update the restored size.
120 gfx::Size full_size = panel->full_size();
121 full_size.set_width(common_width);
122 panel->set_full_size(full_size);
124 // Recompute the bounds.
125 bounds.SetRect(
126 common_x,
128 common_width,
129 panel->expansion_state() == Panel::EXPANDED ?
130 panel->full_size().height() : panel->TitleOnlyHeight());
132 GetStackWindowForPanel(panel)->AddPanelBoundsForBatchUpdate(panel, bounds);
134 y += bounds.height();
137 primary_stack_window_->EndBatchUpdatePanelBounds();
138 if (secondary_stack_window_)
139 secondary_stack_window_->EndBatchUpdatePanelBounds();
142 base::string16 StackedPanelCollection::GetTitle() const {
143 if (panels_.empty())
144 return base::string16();
146 Panel* panel = panels_.front();
147 const extensions::Extension* extension = panel->GetExtension();
148 return base::UTF8ToUTF16(extension && !extension->name().empty() ?
149 extension->name() : panel->app_name());
152 gfx::Image StackedPanelCollection::GetIcon() const {
153 if (panels_.empty())
154 return gfx::Image();
155 return panels_.front()->app_icon();
158 void StackedPanelCollection::PanelBoundsBatchUpdateCompleted() {
159 if (!secondary_stack_window_ || panels_.empty())
160 return;
162 if (top_panel()->in_preview_mode() != bottom_panel()->in_preview_mode() ||
163 primary_stack_window_->IsAnimatingPanelBounds() ||
164 secondary_stack_window_->IsAnimatingPanelBounds())
165 return;
167 // Move all panels from secondary stack window to primary stack window.
168 primary_stack_window_->MergeWith(secondary_stack_window_);
169 secondary_stack_window_->Close();
170 secondary_stack_window_ = NULL;
173 gfx::Rect StackedPanelCollection::GetEnclosingBounds() const {
174 gfx::Rect enclosing_bounds = top_panel()->GetBounds();
175 enclosing_bounds.set_height(
176 bottom_panel()->GetBounds().bottom() - enclosing_bounds.y());
177 return enclosing_bounds;
180 int StackedPanelCollection::MinimizePanelsForSpace(int needed_space) {
181 int available_space = GetCurrentAvailableBottomSpace();
183 // Only the most recently active panel might be active.
184 Panel* active_panel = NULL;
185 if (!most_recently_active_panels_.empty()) {
186 Panel* most_recently_active_panel = most_recently_active_panels_.front();
187 if (most_recently_active_panel->IsActive())
188 active_panel = most_recently_active_panel;
191 for (Panels::const_reverse_iterator iter =
192 most_recently_active_panels_.rbegin();
193 iter != most_recently_active_panels_.rend() &&
194 available_space < needed_space;
195 ++iter) {
196 Panel* current_panel = *iter;
197 if (current_panel != active_panel && !IsPanelMinimized(current_panel)) {
198 available_space +=
199 current_panel->GetBounds().height() - panel::kTitlebarHeight;
200 MinimizePanel(current_panel);
203 return available_space;
206 void StackedPanelCollection::AddPanel(Panel* panel,
207 PositioningMask positioning_mask) {
208 DCHECK_NE(this, panel->collection());
209 panel->set_collection(this);
210 Panel* adjacent_panel = NULL;
211 if (positioning_mask & PanelCollection::TOP_POSITION) {
212 adjacent_panel = top_panel();
213 panels_.push_front(panel);
214 } else {
215 // To fit the new panel within the working area, collapse unfocused panels
216 // in the least recent active order until there is enough space.
217 if (positioning_mask & PanelCollection::COLLAPSE_TO_FIT) {
218 int needed_space = panel->GetBounds().height();
219 int available_space = MinimizePanelsForSpace(needed_space);
220 DCHECK(available_space >= needed_space);
223 adjacent_panel = bottom_panel();
224 panels_.push_back(panel);
227 if (panel->IsActive())
228 most_recently_active_panels_.push_front(panel);
229 else
230 most_recently_active_panels_.push_back(panel);
232 if (adjacent_panel)
233 UpdatePanelCornerStyle(adjacent_panel);
235 // The secondary stack window should be used when one of the following occurs:
236 // 1) Some panels but not all panels are being dragged. This is because
237 // those panels being dragged might not be fully aligned with other panels
238 // not being dragged.
239 // 2) The newly added panel is not fully aligned with the existing panel, in
240 // terms of both x and width.
241 NativePanelStackWindow* stack_window;
242 if (top_panel()->in_preview_mode() == bottom_panel()->in_preview_mode() &&
243 top_panel()->GetBounds().x() == bottom_panel()->GetBounds().x() &&
244 top_panel()->GetBounds().width() == bottom_panel()->GetBounds().width()) {
245 if (!primary_stack_window_)
246 primary_stack_window_ = NativePanelStackWindow::Create(this);
247 stack_window = primary_stack_window_;
248 } else {
249 if (!secondary_stack_window_)
250 secondary_stack_window_ = NativePanelStackWindow::Create(this);
251 stack_window = secondary_stack_window_;
253 stack_window->AddPanel(panel);
255 if ((positioning_mask & NO_LAYOUT_REFRESH) == 0)
256 RefreshLayout();
259 void StackedPanelCollection::RemovePanel(Panel* panel, RemovalReason reason) {
260 bool is_top = panel == top_panel();
261 bool is_bottom = panel == bottom_panel();
263 // If the top panel is being closed, all panels below it should move up. To
264 // do this, the top y position of top panel needs to be tracked first.
265 bool top_panel_closed = false;
266 gfx::Point top_origin;
267 int top_width = 0;
268 if (reason == PanelCollection::PANEL_CLOSED && is_top) {
269 top_panel_closed = true;
270 top_origin = panel->GetBounds().origin();
271 top_width = panel->GetBounds().width();
274 panel->set_collection(NULL);
275 panels_.remove(panel);
276 most_recently_active_panels_.remove(panel);
278 if (is_top) {
279 Panel* new_top_panel = top_panel();
280 if (new_top_panel)
281 UpdatePanelCornerStyle(new_top_panel);
282 } else if (is_bottom) {
283 Panel* new_bottom_panel = bottom_panel();
284 if (new_bottom_panel)
285 UpdatePanelCornerStyle(new_bottom_panel);
288 // If an active panel is being closed, try to focus the next recently active
289 // panel in the stack that is not minimized.
290 if (reason == PanelCollection::PANEL_CLOSED &&
291 panel->IsActive() &&
292 !most_recently_active_panels_.empty()) {
293 for (Panels::const_iterator iter = most_recently_active_panels_.begin();
294 iter != most_recently_active_panels_.end(); ++iter) {
295 Panel* other_panel = *iter;
296 if (!IsPanelMinimized(other_panel)) {
297 other_panel->Activate();
298 break;
303 // If the top panel is closed, move up all other panels to stay at the same
304 // y position as the top panel being closed.
305 if (top_panel_closed)
306 RefreshLayoutWithTopPanelStartingAt(top_origin, top_width);
307 else if (reason == PanelCollection::PANEL_CLOSED)
308 RefreshLayout();
310 // Remove the panel from the corresponding stack window.
311 GetStackWindowForPanel(panel)->RemovePanel(panel);
313 // Close the secondary stack window if no panel is is shown inside it.
314 // Note that we do not need to do this for primary stack window since the
315 // whole stack will be gone when only one panel is left.
316 if (secondary_stack_window_ && secondary_stack_window_->IsEmpty()) {
317 secondary_stack_window_->Close();
318 secondary_stack_window_ = NULL;
322 void StackedPanelCollection::CloseAll() {
323 // Make a copy as closing panels can modify the iterator.
324 Panels panels_copy = panels_;
326 for (Panels::const_iterator iter = panels_copy.begin();
327 iter != panels_copy.end(); ++iter)
328 (*iter)->Close();
330 if (primary_stack_window_) {
331 primary_stack_window_->Close();
332 primary_stack_window_ = NULL;
334 if (secondary_stack_window_) {
335 secondary_stack_window_->Close();
336 secondary_stack_window_ = NULL;
340 void StackedPanelCollection::OnPanelAttentionStateChanged(Panel* panel) {
341 if ((panel->attention_mode() & Panel::USE_SYSTEM_ATTENTION) != 0)
342 primary_stack_window_->DrawSystemAttention(panel->IsDrawingAttention());
345 void StackedPanelCollection::OnPanelTitlebarClicked(
346 Panel* panel, panel::ClickModifier modifier) {
347 bool expanded = panel->expansion_state() == Panel::EXPANDED;
348 if (modifier == panel::APPLY_TO_ALL) {
349 if (expanded)
350 MinimizeAll();
351 else
352 RestoreAll(panel);
353 } else {
354 if (expanded)
355 MinimizePanel(panel);
356 else
357 RestorePanel(panel);
361 void StackedPanelCollection::ResizePanelWindow(
362 Panel* panel,
363 const gfx::Size& preferred_window_size) {
366 void StackedPanelCollection::ActivatePanel(Panel* panel) {
367 // Make sure the panel is expanded when activated so the user input
368 // does not go into a collapsed window.
369 if (panel->IsMinimized())
370 panel->SetExpansionState(Panel::EXPANDED);
373 void StackedPanelCollection::MinimizePanel(Panel* panel) {
374 panel->SetExpansionState(Panel::TITLE_ONLY);
377 void StackedPanelCollection::RestorePanel(Panel* panel) {
378 // Ensure that the panel could fit within the work area after it is expanded.
379 // First, try to collapse the unfocused panel in the least recent active
380 // order in order to get enough space.
381 int needed_space = panel->full_size().height() - panel->TitleOnlyHeight();
382 int available_space = MinimizePanelsForSpace(needed_space);
384 // If there is still not enough space, try to move up the stack.
385 int space_beyond_available = needed_space - available_space;
386 if (space_beyond_available > 0) {
387 int top_available_space = GetCurrentAvailableTopSpace();
388 int move_delta = (space_beyond_available > top_available_space) ?
389 top_available_space : space_beyond_available;
390 for (Panels::const_iterator iter = panels_.begin();
391 iter != panels_.end(); iter++) {
392 Panel* current_panel = *iter;
393 gfx::Rect bounds = current_panel->GetBounds();
394 bounds.set_y(bounds.y() - move_delta);
395 current_panel->SetPanelBounds(bounds);
397 available_space += move_delta;
400 // If there is still not enough space, shrink the restored height to make it
401 // fit at the last resort. Note that the restored height cannot be shrunk less
402 // than the minimum panel height. If this is the case, we will just let it
403 // expand beyond the screen boundary.
404 space_beyond_available = needed_space - available_space;
405 if (space_beyond_available > 0) {
406 gfx::Size full_size = panel->full_size();
407 int reduced_height = full_size.height() - space_beyond_available;
408 if (reduced_height < panel::kPanelMinHeight)
409 reduced_height = panel::kPanelMinHeight;
410 full_size.set_height(reduced_height);
411 panel->set_full_size(full_size);
414 panel->SetExpansionState(Panel::EXPANDED);
417 void StackedPanelCollection::MinimizeAll() {
418 // Set minimizing_all_ to prevent deactivation of each panel when it
419 // is minimized. See comments in OnPanelExpansionStateChanged.
420 base::AutoReset<bool> pin(&minimizing_all_, true);
421 Panel* minimized_active_panel = NULL;
422 for (Panels::const_iterator iter = panels_.begin();
423 iter != panels_.end(); ++iter) {
424 if ((*iter)->IsActive())
425 minimized_active_panel = *iter;
426 MinimizePanel(*iter);
429 // When a single panel is minimized, it is deactivated to ensure that
430 // a minimized panel does not have focus. However, when minimizing all,
431 // the deactivation is only done once after all panels are minimized,
432 // rather than per minimized panel, both for efficiency and to avoid
433 // temporary activations of random not-yet-minimized panels.
434 if (minimized_active_panel) {
435 minimized_active_panel->Deactivate();
436 // Layout will be refreshed in response to (de)activation notification.
440 void StackedPanelCollection::RestoreAll(Panel* panel_clicked) {
441 // Expand the panel being clicked first. This is to make sure at least one
442 // panel that is clicked by the user will be expanded.
443 RestorePanel(panel_clicked);
445 // Try to expand all other panels starting from the most recently active
446 // panel.
447 for (Panels::const_iterator iter = most_recently_active_panels_.begin();
448 iter != most_recently_active_panels_.end(); ++iter) {
449 // If the stack already extends to both top and bottom of the work area,
450 // stop now since we cannot fit any more expanded panels.
451 if (GetCurrentAvailableTopSpace() == 0 &&
452 GetCurrentAvailableBottomSpace() == 0) {
453 break;
456 Panel* panel = *iter;
457 if (panel != panel_clicked)
458 RestorePanel(panel);
462 void StackedPanelCollection::OnMinimizeButtonClicked(
463 Panel* panel, panel::ClickModifier modifier) {
464 // The minimize button is only present in the top panel.
465 DCHECK_EQ(top_panel(), panel);
467 primary_stack_window_->Minimize();
470 void StackedPanelCollection::OnRestoreButtonClicked(
471 Panel* panel, panel::ClickModifier modifier) {
472 NOTREACHED();
475 bool StackedPanelCollection::CanShowMinimizeButton(const Panel* panel) const {
476 // Only the top panel in the stack shows the minimize button.
477 return PanelManager::CanUseSystemMinimize() && panel == top_panel();
480 bool StackedPanelCollection::CanShowRestoreButton(const Panel* panel) const {
481 return false;
484 bool StackedPanelCollection::IsPanelMinimized(const Panel* panel) const {
485 return panel->expansion_state() != Panel::EXPANDED;
488 bool StackedPanelCollection::UsesAlwaysOnTopPanels() const {
489 return false;
492 void StackedPanelCollection::SavePanelPlacement(Panel* panel) {
493 DCHECK(!saved_panel_placement_.panel);
494 saved_panel_placement_.panel = panel;
496 if (top_panel() != panel)
497 saved_panel_placement_.top_panel = top_panel();
498 else
499 saved_panel_placement_.position = panel->GetBounds().origin();
501 saved_panel_placement_.top_panel = top_panel() != panel ? top_panel() : NULL;
504 void StackedPanelCollection::RestorePanelToSavedPlacement() {
505 DCHECK(saved_panel_placement_.panel);
507 if (saved_panel_placement_.top_panel) {
508 // Restore the top panel if it has been moved out of the stack. This could
509 // happen when there're 2 panels in the stack and the bottom panel is being
510 // dragged out of the stack and thus cause both panels become detached.
511 if (saved_panel_placement_.top_panel->stack() != this) {
512 DCHECK_EQ(PanelCollection::DETACHED,
513 saved_panel_placement_.top_panel->collection()->type());
514 panel_manager_->MovePanelToCollection(
515 saved_panel_placement_.top_panel,
516 this,
517 static_cast<PanelCollection::PositioningMask>(
518 PanelCollection::TOP_POSITION |
519 PanelCollection::NO_LAYOUT_REFRESH));
521 RefreshLayout();
522 } else {
523 // Restore the position when the top panel is being dragged.
524 DCHECK_EQ(top_panel(), saved_panel_placement_.panel);
525 RefreshLayoutWithTopPanelStartingAt(saved_panel_placement_.position,
526 top_panel()->GetBounds().width());
529 DiscardSavedPanelPlacement();
532 void StackedPanelCollection::DiscardSavedPanelPlacement() {
533 DCHECK(saved_panel_placement_.panel);
534 saved_panel_placement_.panel = NULL;
535 saved_panel_placement_.top_panel = NULL;
538 panel::Resizability StackedPanelCollection::GetPanelResizability(
539 const Panel* panel) const {
540 // The panel in the stack can be resized by the following rules:
541 // * If collapsed, it can only be resized by its left or right edge.
542 // * Otherwise, it can be resized by its left or right edge plus:
543 // % top edge and corners, if it is at the top;
544 // % bottom edge, if it is not at the bottom.
545 // % bottom edge and corners, if it is at the bottom.
546 panel::Resizability resizability = static_cast<panel::Resizability>(
547 panel::RESIZABLE_LEFT | panel::RESIZABLE_RIGHT);
548 if (panel->IsMinimized())
549 return resizability;
550 if (panel == top_panel()) {
551 resizability = static_cast<panel::Resizability>(resizability |
552 panel::RESIZABLE_TOP | panel::RESIZABLE_TOP_LEFT |
553 panel::RESIZABLE_TOP_RIGHT);
555 if (panel == bottom_panel()) {
556 resizability = static_cast<panel::Resizability>(resizability |
557 panel::RESIZABLE_BOTTOM | panel::RESIZABLE_BOTTOM_LEFT |
558 panel::RESIZABLE_BOTTOM_RIGHT);
559 } else {
560 resizability = static_cast<panel::Resizability>(resizability |
561 panel::RESIZABLE_BOTTOM);
563 return resizability;
566 void StackedPanelCollection::OnPanelResizedByMouse(
567 Panel* resized_panel, const gfx::Rect& new_bounds) {
568 resized_panel->set_full_size(new_bounds.size());
570 DCHECK(!secondary_stack_window_);
571 primary_stack_window_->BeginBatchUpdatePanelBounds(false);
573 // The delta x and width can be computed from the difference between
574 // the panel being resized and any other panel.
575 Panel* other_panel = resized_panel == top_panel() ? bottom_panel()
576 : top_panel();
577 gfx::Rect other_bounds = other_panel->GetBounds();
578 int delta_x = new_bounds.x() - other_bounds.x();
579 int delta_width = new_bounds.width() - other_bounds.width();
581 gfx::Rect previous_bounds;
582 bool resized_panel_found = false;
583 bool panel_below_resized_panel_updated = false;
584 for (Panels::const_iterator iter = panels_.begin();
585 iter != panels_.end(); iter++) {
586 Panel* panel = *iter;
587 if (panel == resized_panel) {
588 // |new_bounds| should be used since the panel bounds have not been
589 // updated yet.
590 previous_bounds = new_bounds;
591 resized_panel_found = true;
592 primary_stack_window_->AddPanelBoundsForBatchUpdate(panel, new_bounds);
593 continue;
596 gfx::Rect bounds = panel->GetBounds();
597 bounds.set_x(bounds.x() + delta_x);
598 bounds.set_width(bounds.width() + delta_width);
600 // If the panel below the panel being resized is expanded, update its
601 // height to offset the height change of the panel being resized.
602 // For example, the stack has P1 and P2 (from top to bottom). P1's height
603 // is 100 and P2's height is 120. If P1's bottom increases by 10, P2's
604 // height needs to shrink by 10.
605 if (resized_panel_found) {
606 if (!panel_below_resized_panel_updated && !panel->IsMinimized()) {
607 int old_bottom = bounds.bottom();
608 bounds.set_y(previous_bounds.bottom());
609 bounds.set_height(old_bottom - bounds.y());
610 } else {
611 bounds.set_y(previous_bounds.bottom());
613 panel_below_resized_panel_updated = true;
616 if (!panel->IsMinimized())
617 panel->set_full_size(bounds.size());
619 primary_stack_window_->AddPanelBoundsForBatchUpdate(panel, bounds);
620 previous_bounds = bounds;
623 primary_stack_window_->EndBatchUpdatePanelBounds();
626 bool StackedPanelCollection::HasPanel(Panel* panel) const {
627 return std::find(panels_.begin(), panels_.end(), panel) != panels_.end();
630 void StackedPanelCollection::UpdatePanelOnCollectionChange(Panel* panel) {
631 panel->set_attention_mode(
632 static_cast<Panel::AttentionMode>(Panel::USE_PANEL_ATTENTION |
633 Panel::USE_SYSTEM_ATTENTION));
634 panel->ShowShadow(false);
635 panel->UpdateMinimizeRestoreButtonVisibility();
636 UpdatePanelCornerStyle(panel);
639 void StackedPanelCollection::OnPanelExpansionStateChanged(Panel* panel) {
640 DCHECK_NE(Panel::MINIMIZED, panel->expansion_state());
642 // Ensure minimized panel does not get the focus. If minimizing all,
643 // the active panel will be deactivated once when all panels are minimized
644 // rather than per minimized panel.
645 if (panel->expansion_state() != Panel::EXPANDED && !minimizing_all_ &&
646 panel->IsActive()) {
647 panel->Deactivate();
650 // The bounds change per expansion state will be done in RefreshLayout.
651 RefreshLayout();
654 void StackedPanelCollection::OnPanelActiveStateChanged(Panel* panel) {
655 if (!panel->IsActive())
656 return;
658 // Move the panel to the front if not yet.
659 Panels::iterator iter = std::find(most_recently_active_panels_.begin(),
660 most_recently_active_panels_.end(), panel);
661 DCHECK(iter != most_recently_active_panels_.end());
662 if (iter != most_recently_active_panels_.begin()) {
663 most_recently_active_panels_.erase(iter);
664 most_recently_active_panels_.push_front(panel);
667 GetStackWindowForPanel(panel)->OnPanelActivated(panel);
670 gfx::Rect StackedPanelCollection::GetInitialPanelBounds(
671 const gfx::Rect& requested_bounds) const {
672 DCHECK(!panels_.empty());
673 gfx::Rect bottom_panel_bounds = bottom_panel()->GetBounds();
674 return gfx::Rect(bottom_panel_bounds.x(),
675 bottom_panel_bounds.bottom(),
676 bottom_panel_bounds.width(),
677 requested_bounds.height());
680 Panel* StackedPanelCollection::GetPanelAbove(Panel* panel) const {
681 DCHECK(panel);
683 if (panels_.size() < 2)
684 return NULL;
685 Panels::const_iterator iter = panels_.begin();
686 Panel* above_panel = *iter;
687 for (; iter != panels_.end(); ++iter) {
688 if (*iter == panel)
689 return above_panel;
690 above_panel = *iter;
692 return NULL;
695 Panel* StackedPanelCollection::GetPanelBelow(Panel* panel) const {
696 DCHECK(panel);
698 if (panels_.size() < 2)
699 return NULL;
700 Panels::const_iterator iter =
701 std::find(panels_.begin(), panels_.end(), panel);
702 if (iter == panels_.end())
703 return NULL;
704 ++iter;
705 return iter == panels_.end() ? NULL : *iter;
708 void StackedPanelCollection::MoveAllDraggingPanelsInstantly(
709 const gfx::Vector2d& delta_origin) {
710 for (Panels::const_iterator iter = panels_.begin();
711 iter != panels_.end(); iter++) {
712 Panel* panel = *iter;
713 if (panel->in_preview_mode()) {
714 GetStackWindowForPanel(panel)->MovePanelsBy(delta_origin);
715 return;
720 bool StackedPanelCollection::IsMinimized() const {
721 return primary_stack_window_->IsMinimized();
724 bool StackedPanelCollection::IsAnimatingPanelBounds(Panel* panel) const {
725 return GetStackWindowForPanel(panel)->IsAnimatingPanelBounds();
728 void StackedPanelCollection::UpdatePanelCornerStyle(Panel* panel) {
729 panel::CornerStyle corner_style;
730 bool at_top = panel == top_panel();
731 bool at_bottom = panel == bottom_panel();
732 if (at_top && at_bottom)
733 corner_style = panel::ALL_ROUNDED;
734 else if (at_top)
735 corner_style = panel::TOP_ROUNDED;
736 else if (at_bottom)
737 corner_style = panel::BOTTOM_ROUNDED;
738 else
739 corner_style = panel::NOT_ROUNDED;
740 panel->SetWindowCornerStyle(corner_style);
743 gfx::Rect StackedPanelCollection::GetWorkArea() const {
744 if (panels_.empty())
745 return panel_manager_->display_settings_provider()->GetPrimaryWorkArea();
746 return panel_manager_->display_settings_provider()->GetWorkAreaMatching(
747 GetEnclosingBounds());
750 int StackedPanelCollection::GetCurrentAvailableTopSpace() const {
751 gfx::Rect work_area = GetWorkArea();
752 if (panels_.empty())
753 return work_area.height();
755 int available_space = top_panel()->GetBounds().y() - work_area.y();
756 if (available_space < 0)
757 available_space = 0;
758 return available_space;
761 int StackedPanelCollection::GetCurrentAvailableBottomSpace() const {
762 gfx::Rect work_area = GetWorkArea();
763 if (panels_.empty())
764 return work_area.height();
766 int available_space = work_area.bottom() -
767 bottom_panel()->GetBounds().bottom();
768 if (available_space < 0)
769 available_space = 0;
770 return available_space;
773 int StackedPanelCollection::GetMaximiumAvailableBottomSpace() const {
774 gfx::Rect work_area = GetWorkArea();
775 if (panels_.empty())
776 return work_area.height();
778 int bottom = top_panel()->GetBounds().y();
779 for (Panels::const_iterator iter = panels_.begin();
780 iter != panels_.end(); iter++) {
781 Panel* panel = *iter;
782 // Only the most recently active panel might be active.
783 if (iter == panels_.begin() && panel->IsActive())
784 bottom += panel->GetBounds().height();
785 else
786 bottom += panel::kTitlebarHeight;
788 int available_space = work_area.bottom() - bottom;
789 if (available_space < 0)
790 available_space = 0;
791 return available_space;
794 NativePanelStackWindow* StackedPanelCollection::GetStackWindowForPanel(
795 Panel* panel) const {
796 return secondary_stack_window_ && secondary_stack_window_->HasPanel(panel) ?
797 secondary_stack_window_ : primary_stack_window_;