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"
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() {
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() {
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
) {
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
);
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
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();
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.
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 {
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 {
155 return panels_
.front()->app_icon();
158 void StackedPanelCollection::PanelBoundsBatchUpdateCompleted() {
159 if (!secondary_stack_window_
|| panels_
.empty())
162 if (top_panel()->in_preview_mode() != bottom_panel()->in_preview_mode() ||
163 primary_stack_window_
->IsAnimatingPanelBounds() ||
164 secondary_stack_window_
->IsAnimatingPanelBounds())
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
;
196 Panel
* current_panel
= *iter
;
197 if (current_panel
!= active_panel
&& !IsPanelMinimized(current_panel
)) {
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
);
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
);
230 most_recently_active_panels_
.push_back(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_
;
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)
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
;
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
);
279 Panel
* new_top_panel
= 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
&&
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();
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
)
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
)
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
) {
355 MinimizePanel(panel
);
361 void StackedPanelCollection::ResizePanelWindow(
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
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) {
456 Panel
* panel
= *iter
;
457 if (panel
!= panel_clicked
)
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
) {
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 {
484 bool StackedPanelCollection::IsPanelMinimized(const Panel
* panel
) const {
485 return panel
->expansion_state() != Panel::EXPANDED
;
488 bool StackedPanelCollection::UsesAlwaysOnTopPanels() const {
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();
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
,
517 static_cast<PanelCollection::PositioningMask
>(
518 PanelCollection::TOP_POSITION
|
519 PanelCollection::NO_LAYOUT_REFRESH
));
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())
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
);
560 resizability
= static_cast<panel::Resizability
>(resizability
|
561 panel::RESIZABLE_BOTTOM
);
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()
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
590 previous_bounds
= new_bounds
;
591 resized_panel_found
= true;
592 primary_stack_window_
->AddPanelBoundsForBatchUpdate(panel
, new_bounds
);
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());
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_
&&
650 // The bounds change per expansion state will be done in RefreshLayout.
654 void StackedPanelCollection::OnPanelActiveStateChanged(Panel
* panel
) {
655 if (!panel
->IsActive())
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 {
683 if (panels_
.size() < 2)
685 Panels::const_iterator iter
= panels_
.begin();
686 Panel
* above_panel
= *iter
;
687 for (; iter
!= panels_
.end(); ++iter
) {
695 Panel
* StackedPanelCollection::GetPanelBelow(Panel
* panel
) const {
698 if (panels_
.size() < 2)
700 Panels::const_iterator iter
=
701 std::find(panels_
.begin(), panels_
.end(), panel
);
702 if (iter
== panels_
.end())
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
);
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
;
735 corner_style
= panel::TOP_ROUNDED
;
737 corner_style
= panel::BOTTOM_ROUNDED
;
739 corner_style
= panel::NOT_ROUNDED
;
740 panel
->SetWindowCornerStyle(corner_style
);
743 gfx::Rect
StackedPanelCollection::GetWorkArea() const {
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();
753 return work_area
.height();
755 int available_space
= top_panel()->GetBounds().y() - work_area
.y();
756 if (available_space
< 0)
758 return available_space
;
761 int StackedPanelCollection::GetCurrentAvailableBottomSpace() const {
762 gfx::Rect work_area
= GetWorkArea();
764 return work_area
.height();
766 int available_space
= work_area
.bottom() -
767 bottom_panel()->GetBounds().bottom();
768 if (available_space
< 0)
770 return available_space
;
773 int StackedPanelCollection::GetMaximiumAvailableBottomSpace() const {
774 gfx::Rect work_area
= GetWorkArea();
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();
786 bottom
+= panel::kTitlebarHeight
;
788 int available_space
= work_area
.bottom() - bottom
;
789 if (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_
;