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 "chrome/common/extensions/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 string16
StackedPanelCollection::GetTitle() const {
146 Panel
* panel
= panels_
.front();
147 const extensions::Extension
* extension
= panel
->GetExtension();
148 return UTF8ToUTF16(extension
&& !extension
->name().empty() ?
149 extension
->name() : panel
->app_name());
152 void StackedPanelCollection::PanelBoundsBatchUpdateCompleted() {
153 if (!secondary_stack_window_
|| panels_
.empty())
156 if (top_panel()->in_preview_mode() != bottom_panel()->in_preview_mode() ||
157 primary_stack_window_
->IsAnimatingPanelBounds() ||
158 secondary_stack_window_
->IsAnimatingPanelBounds())
161 // Move all panels from secondary stack window to primary stack window.
162 primary_stack_window_
->MergeWith(secondary_stack_window_
);
163 secondary_stack_window_
->Close();
164 secondary_stack_window_
= NULL
;
167 gfx::Rect
StackedPanelCollection::GetEnclosingBounds() const {
168 gfx::Rect enclosing_bounds
= top_panel()->GetBounds();
169 enclosing_bounds
.set_height(
170 bottom_panel()->GetBounds().bottom() - enclosing_bounds
.y());
171 return enclosing_bounds
;
174 int StackedPanelCollection::MinimizePanelsForSpace(int needed_space
) {
175 int available_space
= GetCurrentAvailableBottomSpace();
177 // Only the most recently active panel might be active.
178 Panel
* active_panel
= NULL
;
179 if (!most_recently_active_panels_
.empty()) {
180 Panel
* most_recently_active_panel
= most_recently_active_panels_
.front();
181 if (most_recently_active_panel
->IsActive())
182 active_panel
= most_recently_active_panel
;
185 for (Panels::const_reverse_iterator iter
=
186 most_recently_active_panels_
.rbegin();
187 iter
!= most_recently_active_panels_
.rend() &&
188 available_space
< needed_space
;
190 Panel
* current_panel
= *iter
;
191 if (current_panel
!= active_panel
&& !IsPanelMinimized(current_panel
)) {
193 current_panel
->GetBounds().height() - panel::kTitlebarHeight
;
194 MinimizePanel(current_panel
);
197 return available_space
;
200 void StackedPanelCollection::AddPanel(Panel
* panel
,
201 PositioningMask positioning_mask
) {
202 DCHECK_NE(this, panel
->collection());
203 panel
->set_collection(this);
204 Panel
* adjacent_panel
= NULL
;
205 if (positioning_mask
& PanelCollection::TOP_POSITION
) {
206 adjacent_panel
= top_panel();
207 panels_
.push_front(panel
);
209 // To fit the new panel within the working area, collapse unfocused panels
210 // in the least recent active order until there is enough space.
211 if (positioning_mask
& PanelCollection::COLLAPSE_TO_FIT
) {
212 int needed_space
= panel
->GetBounds().height();
213 int available_space
= MinimizePanelsForSpace(needed_space
);
214 DCHECK(available_space
>= needed_space
);
217 adjacent_panel
= bottom_panel();
218 panels_
.push_back(panel
);
221 if (panel
->IsActive())
222 most_recently_active_panels_
.push_front(panel
);
224 most_recently_active_panels_
.push_back(panel
);
227 UpdatePanelCornerStyle(adjacent_panel
);
229 // The secondary stack window should be used when one of the following occurs:
230 // 1) Some panels but not all panels are being dragged. This is because
231 // those panels being dragged might not be fully aligned with other panels
232 // not being dragged.
233 // 2) The newly added panel is not fully aligned with the existing panel, in
234 // terms of both x and width.
235 NativePanelStackWindow
* stack_window
;
236 if (top_panel()->in_preview_mode() == bottom_panel()->in_preview_mode() &&
237 top_panel()->GetBounds().x() == bottom_panel()->GetBounds().x() &&
238 top_panel()->GetBounds().width() == bottom_panel()->GetBounds().width()) {
239 if (!primary_stack_window_
)
240 primary_stack_window_
= NativePanelStackWindow::Create(this);
241 stack_window
= primary_stack_window_
;
243 if (!secondary_stack_window_
)
244 secondary_stack_window_
= NativePanelStackWindow::Create(this);
245 stack_window
= secondary_stack_window_
;
247 stack_window
->AddPanel(panel
);
249 if ((positioning_mask
& NO_LAYOUT_REFRESH
) == 0)
253 void StackedPanelCollection::RemovePanel(Panel
* panel
, RemovalReason reason
) {
254 bool is_top
= panel
== top_panel();
255 bool is_bottom
= panel
== bottom_panel();
257 // If the top panel is being closed, all panels below it should move up. To
258 // do this, the top y position of top panel needs to be tracked first.
259 bool top_panel_closed
= false;
260 gfx::Point top_origin
;
262 if (reason
== PanelCollection::PANEL_CLOSED
&& is_top
) {
263 top_panel_closed
= true;
264 top_origin
= panel
->GetBounds().origin();
265 top_width
= panel
->GetBounds().width();
268 panel
->set_collection(NULL
);
269 panels_
.remove(panel
);
270 most_recently_active_panels_
.remove(panel
);
273 Panel
* new_top_panel
= top_panel();
275 UpdatePanelCornerStyle(new_top_panel
);
276 } else if (is_bottom
) {
277 Panel
* new_bottom_panel
= bottom_panel();
278 if (new_bottom_panel
)
279 UpdatePanelCornerStyle(new_bottom_panel
);
282 // If an active panel is being closed, try to focus the next recently active
283 // panel in the stack that is not minimized.
284 if (reason
== PanelCollection::PANEL_CLOSED
&&
286 !most_recently_active_panels_
.empty()) {
287 for (Panels::const_iterator iter
= most_recently_active_panels_
.begin();
288 iter
!= most_recently_active_panels_
.end(); ++iter
) {
289 Panel
* other_panel
= *iter
;
290 if (!IsPanelMinimized(other_panel
)) {
291 other_panel
->Activate();
297 // If the top panel is closed, move up all other panels to stay at the same
298 // y position as the top panel being closed.
299 if (top_panel_closed
)
300 RefreshLayoutWithTopPanelStartingAt(top_origin
, top_width
);
301 else if (reason
== PanelCollection::PANEL_CLOSED
)
304 // Remove the panel from the corresponding stack window.
305 GetStackWindowForPanel(panel
)->RemovePanel(panel
);
307 // Close the secondary stack window if no panel is is shown inside it.
308 // Note that we do not need to do this for primary stack window since the
309 // whole stack will be gone when only one panel is left.
310 if (secondary_stack_window_
&& secondary_stack_window_
->IsEmpty()) {
311 secondary_stack_window_
->Close();
312 secondary_stack_window_
= NULL
;
316 void StackedPanelCollection::CloseAll() {
317 // Make a copy as closing panels can modify the iterator.
318 Panels panels_copy
= panels_
;
320 for (Panels::const_iterator iter
= panels_copy
.begin();
321 iter
!= panels_copy
.end(); ++iter
)
324 if (primary_stack_window_
) {
325 primary_stack_window_
->Close();
326 primary_stack_window_
= NULL
;
328 if (secondary_stack_window_
) {
329 secondary_stack_window_
->Close();
330 secondary_stack_window_
= NULL
;
334 void StackedPanelCollection::OnPanelAttentionStateChanged(Panel
* panel
) {
335 if ((panel
->attention_mode() & Panel::USE_SYSTEM_ATTENTION
) != 0)
336 primary_stack_window_
->DrawSystemAttention(panel
->IsDrawingAttention());
339 void StackedPanelCollection::OnPanelTitlebarClicked(
340 Panel
* panel
, panel::ClickModifier modifier
) {
341 bool expanded
= panel
->expansion_state() == Panel::EXPANDED
;
342 if (modifier
== panel::APPLY_TO_ALL
) {
349 MinimizePanel(panel
);
355 void StackedPanelCollection::ResizePanelWindow(
357 const gfx::Size
& preferred_window_size
) {
360 void StackedPanelCollection::ActivatePanel(Panel
* panel
) {
361 // Make sure the panel is expanded when activated so the user input
362 // does not go into a collapsed window.
363 if (panel
->IsMinimized())
364 panel
->SetExpansionState(Panel::EXPANDED
);
367 void StackedPanelCollection::MinimizePanel(Panel
* panel
) {
368 panel
->SetExpansionState(Panel::TITLE_ONLY
);
371 void StackedPanelCollection::RestorePanel(Panel
* panel
) {
372 // Ensure that the panel could fit within the work area after it is expanded.
373 // First, try to collapse the unfocused panel in the least recent active
374 // order in order to get enough space.
375 int needed_space
= panel
->full_size().height() - panel
->TitleOnlyHeight();
376 int available_space
= MinimizePanelsForSpace(needed_space
);
378 // If there is still not enough space, try to move up the stack.
379 int space_beyond_available
= needed_space
- available_space
;
380 if (space_beyond_available
> 0) {
381 int top_available_space
= GetCurrentAvailableTopSpace();
382 int move_delta
= (space_beyond_available
> top_available_space
) ?
383 top_available_space
: space_beyond_available
;
384 for (Panels::const_iterator iter
= panels_
.begin();
385 iter
!= panels_
.end(); iter
++) {
386 Panel
* current_panel
= *iter
;
387 gfx::Rect bounds
= current_panel
->GetBounds();
388 bounds
.set_y(bounds
.y() - move_delta
);
389 current_panel
->SetPanelBounds(bounds
);
391 available_space
+= move_delta
;
394 // If there is still not enough space, shrink the restored height to make it
395 // fit at the last resort. Note that the restored height cannot be shrunk less
396 // than the minimum panel height. If this is the case, we will just let it
397 // expand beyond the screen boundary.
398 space_beyond_available
= needed_space
- available_space
;
399 if (space_beyond_available
> 0) {
400 gfx::Size full_size
= panel
->full_size();
401 int reduced_height
= full_size
.height() - space_beyond_available
;
402 if (reduced_height
< panel::kPanelMinHeight
)
403 reduced_height
= panel::kPanelMinHeight
;
404 full_size
.set_height(reduced_height
);
405 panel
->set_full_size(full_size
);
408 panel
->SetExpansionState(Panel::EXPANDED
);
411 void StackedPanelCollection::MinimizeAll() {
412 // Set minimizing_all_ to prevent deactivation of each panel when it
413 // is minimized. See comments in OnPanelExpansionStateChanged.
414 base::AutoReset
<bool> pin(&minimizing_all_
, true);
415 Panel
* minimized_active_panel
= NULL
;
416 for (Panels::const_iterator iter
= panels_
.begin();
417 iter
!= panels_
.end(); ++iter
) {
418 if ((*iter
)->IsActive())
419 minimized_active_panel
= *iter
;
420 MinimizePanel(*iter
);
423 // When a single panel is minimized, it is deactivated to ensure that
424 // a minimized panel does not have focus. However, when minimizing all,
425 // the deactivation is only done once after all panels are minimized,
426 // rather than per minimized panel, both for efficiency and to avoid
427 // temporary activations of random not-yet-minimized panels.
428 if (minimized_active_panel
) {
429 minimized_active_panel
->Deactivate();
430 // Layout will be refreshed in response to (de)activation notification.
434 void StackedPanelCollection::RestoreAll(Panel
* panel_clicked
) {
435 // Expand the panel being clicked first. This is to make sure at least one
436 // panel that is clicked by the user will be expanded.
437 RestorePanel(panel_clicked
);
439 // Try to expand all other panels starting from the most recently active
441 for (Panels::const_iterator iter
= most_recently_active_panels_
.begin();
442 iter
!= most_recently_active_panels_
.end(); ++iter
) {
443 // If the stack already extends to both top and bottom of the work area,
444 // stop now since we cannot fit any more expanded panels.
445 if (GetCurrentAvailableTopSpace() == 0 &&
446 GetCurrentAvailableBottomSpace() == 0) {
450 Panel
* panel
= *iter
;
451 if (panel
!= panel_clicked
)
456 void StackedPanelCollection::OnMinimizeButtonClicked(
457 Panel
* panel
, panel::ClickModifier modifier
) {
458 // The minimize button is only present in the top panel.
459 DCHECK_EQ(top_panel(), panel
);
461 primary_stack_window_
->Minimize();
464 void StackedPanelCollection::OnRestoreButtonClicked(
465 Panel
* panel
, panel::ClickModifier modifier
) {
469 bool StackedPanelCollection::CanShowMinimizeButton(const Panel
* panel
) const {
470 // Only the top panel in the stack shows the minimize button.
471 return PanelManager::CanUseSystemMinimize() && panel
== top_panel();
474 bool StackedPanelCollection::CanShowRestoreButton(const Panel
* panel
) const {
478 bool StackedPanelCollection::IsPanelMinimized(const Panel
* panel
) const {
479 return panel
->expansion_state() != Panel::EXPANDED
;
482 bool StackedPanelCollection::UsesAlwaysOnTopPanels() const {
486 void StackedPanelCollection::SavePanelPlacement(Panel
* panel
) {
487 DCHECK(!saved_panel_placement_
.panel
);
488 saved_panel_placement_
.panel
= panel
;
490 if (top_panel() != panel
)
491 saved_panel_placement_
.top_panel
= top_panel();
493 saved_panel_placement_
.position
= panel
->GetBounds().origin();
495 saved_panel_placement_
.top_panel
= top_panel() != panel
? top_panel() : NULL
;
498 void StackedPanelCollection::RestorePanelToSavedPlacement() {
499 DCHECK(saved_panel_placement_
.panel
);
501 if (saved_panel_placement_
.top_panel
) {
502 // Restore the top panel if it has been moved out of the stack. This could
503 // happen when there're 2 panels in the stack and the bottom panel is being
504 // dragged out of the stack and thus cause both panels become detached.
505 if (saved_panel_placement_
.top_panel
->stack() != this) {
506 DCHECK_EQ(PanelCollection::DETACHED
,
507 saved_panel_placement_
.top_panel
->collection()->type());
508 panel_manager_
->MovePanelToCollection(
509 saved_panel_placement_
.top_panel
,
511 static_cast<PanelCollection::PositioningMask
>(
512 PanelCollection::TOP_POSITION
|
513 PanelCollection::NO_LAYOUT_REFRESH
));
517 // Restore the position when the top panel is being dragged.
518 DCHECK_EQ(top_panel(), saved_panel_placement_
.panel
);
519 RefreshLayoutWithTopPanelStartingAt(saved_panel_placement_
.position
,
520 top_panel()->GetBounds().width());
523 DiscardSavedPanelPlacement();
526 void StackedPanelCollection::DiscardSavedPanelPlacement() {
527 DCHECK(saved_panel_placement_
.panel
);
528 saved_panel_placement_
.panel
= NULL
;
529 saved_panel_placement_
.top_panel
= NULL
;
532 panel::Resizability
StackedPanelCollection::GetPanelResizability(
533 const Panel
* panel
) const {
534 // The panel in the stack can be resized by the following rules:
535 // * If collapsed, it can only be resized by its left or right edge.
536 // * Otherwise, it can be resized by its left or right edge plus:
537 // % top edge and corners, if it is at the top;
538 // % bottom edge, if it is not at the bottom.
539 // % bottom edge and corners, if it is at the bottom.
540 panel::Resizability resizability
= static_cast<panel::Resizability
>(
541 panel::RESIZABLE_LEFT
| panel::RESIZABLE_RIGHT
);
542 if (panel
->IsMinimized())
544 if (panel
== top_panel()) {
545 resizability
= static_cast<panel::Resizability
>(resizability
|
546 panel::RESIZABLE_TOP
| panel::RESIZABLE_TOP_LEFT
|
547 panel::RESIZABLE_TOP_RIGHT
);
549 if (panel
== bottom_panel()) {
550 resizability
= static_cast<panel::Resizability
>(resizability
|
551 panel::RESIZABLE_BOTTOM
| panel::RESIZABLE_BOTTOM_LEFT
|
552 panel::RESIZABLE_BOTTOM_RIGHT
);
554 resizability
= static_cast<panel::Resizability
>(resizability
|
555 panel::RESIZABLE_BOTTOM
);
560 void StackedPanelCollection::OnPanelResizedByMouse(
561 Panel
* resized_panel
, const gfx::Rect
& new_bounds
) {
562 resized_panel
->set_full_size(new_bounds
.size());
564 DCHECK(!secondary_stack_window_
);
565 primary_stack_window_
->BeginBatchUpdatePanelBounds(false);
567 // The delta x and width can be computed from the difference between
568 // the panel being resized and any other panel.
569 Panel
* other_panel
= resized_panel
== top_panel() ? bottom_panel()
571 gfx::Rect other_bounds
= other_panel
->GetBounds();
572 int delta_x
= new_bounds
.x() - other_bounds
.x();
573 int delta_width
= new_bounds
.width() - other_bounds
.width();
575 gfx::Rect previous_bounds
;
576 bool resized_panel_found
= false;
577 bool panel_below_resized_panel_updated
= false;
578 for (Panels::const_iterator iter
= panels_
.begin();
579 iter
!= panels_
.end(); iter
++) {
580 Panel
* panel
= *iter
;
581 if (panel
== resized_panel
) {
582 // |new_bounds| should be used since the panel bounds have not been
584 previous_bounds
= new_bounds
;
585 resized_panel_found
= true;
586 primary_stack_window_
->AddPanelBoundsForBatchUpdate(panel
, new_bounds
);
590 gfx::Rect bounds
= panel
->GetBounds();
591 bounds
.set_x(bounds
.x() + delta_x
);
592 bounds
.set_width(bounds
.width() + delta_width
);
594 // If the panel below the panel being resized is expanded, update its
595 // height to offset the height change of the panel being resized.
596 // For example, the stack has P1 and P2 (from top to bottom). P1's height
597 // is 100 and P2's height is 120. If P1's bottom increases by 10, P2's
598 // height needs to shrink by 10.
599 if (resized_panel_found
) {
600 if (!panel_below_resized_panel_updated
&& !panel
->IsMinimized()) {
601 int old_bottom
= bounds
.bottom();
602 bounds
.set_y(previous_bounds
.bottom());
603 bounds
.set_height(old_bottom
- bounds
.y());
605 bounds
.set_y(previous_bounds
.bottom());
607 panel_below_resized_panel_updated
= true;
610 if (!panel
->IsMinimized())
611 panel
->set_full_size(bounds
.size());
613 primary_stack_window_
->AddPanelBoundsForBatchUpdate(panel
, bounds
);
614 previous_bounds
= bounds
;
617 primary_stack_window_
->EndBatchUpdatePanelBounds();
620 bool StackedPanelCollection::HasPanel(Panel
* panel
) const {
621 return std::find(panels_
.begin(), panels_
.end(), panel
) != panels_
.end();
624 void StackedPanelCollection::UpdatePanelOnCollectionChange(Panel
* panel
) {
625 panel
->set_attention_mode(
626 static_cast<Panel::AttentionMode
>(Panel::USE_PANEL_ATTENTION
|
627 Panel::USE_SYSTEM_ATTENTION
));
628 panel
->ShowShadow(false);
629 panel
->EnableResizeByMouse(true);
630 panel
->UpdateMinimizeRestoreButtonVisibility();
631 UpdatePanelCornerStyle(panel
);
634 void StackedPanelCollection::OnPanelExpansionStateChanged(Panel
* panel
) {
635 DCHECK_NE(Panel::MINIMIZED
, panel
->expansion_state());
637 // Ensure minimized panel does not get the focus. If minimizing all,
638 // the active panel will be deactivated once when all panels are minimized
639 // rather than per minimized panel.
640 if (panel
->expansion_state() != Panel::EXPANDED
&& !minimizing_all_
&&
645 // The bounds change per expansion state will be done in RefreshLayout.
649 void StackedPanelCollection::OnPanelActiveStateChanged(Panel
* panel
) {
650 if (!panel
->IsActive())
653 // Move the panel to the front if not yet.
654 Panels::iterator iter
= std::find(most_recently_active_panels_
.begin(),
655 most_recently_active_panels_
.end(), panel
);
656 DCHECK(iter
!= most_recently_active_panels_
.end());
657 if (iter
!= most_recently_active_panels_
.begin()) {
658 most_recently_active_panels_
.erase(iter
);
659 most_recently_active_panels_
.push_front(panel
);
662 GetStackWindowForPanel(panel
)->OnPanelActivated(panel
);
665 gfx::Rect
StackedPanelCollection::GetInitialPanelBounds(
666 const gfx::Rect
& requested_bounds
) const {
667 DCHECK(!panels_
.empty());
668 gfx::Rect bottom_panel_bounds
= bottom_panel()->GetBounds();
669 return gfx::Rect(bottom_panel_bounds
.x(),
670 bottom_panel_bounds
.bottom(),
671 bottom_panel_bounds
.width(),
672 requested_bounds
.height());
675 Panel
* StackedPanelCollection::GetPanelAbove(Panel
* panel
) const {
678 if (panels_
.size() < 2)
680 Panels::const_iterator iter
= panels_
.begin();
681 Panel
* above_panel
= *iter
;
682 for (; iter
!= panels_
.end(); ++iter
) {
690 Panel
* StackedPanelCollection::GetPanelBelow(Panel
* panel
) const {
693 if (panels_
.size() < 2)
695 Panels::const_iterator iter
=
696 std::find(panels_
.begin(), panels_
.end(), panel
);
697 if (iter
== panels_
.end())
700 return iter
== panels_
.end() ? NULL
: *iter
;
703 void StackedPanelCollection::MoveAllDraggingPanelsInstantly(
704 const gfx::Vector2d
& delta_origin
) {
705 for (Panels::const_iterator iter
= panels_
.begin();
706 iter
!= panels_
.end(); iter
++) {
707 Panel
* panel
= *iter
;
708 if (panel
->in_preview_mode()) {
709 GetStackWindowForPanel(panel
)->MovePanelsBy(delta_origin
);
715 bool StackedPanelCollection::IsMinimized() const {
716 return primary_stack_window_
->IsMinimized();
719 bool StackedPanelCollection::IsAnimatingPanelBounds(Panel
* panel
) const {
720 return GetStackWindowForPanel(panel
)->IsAnimatingPanelBounds();
723 void StackedPanelCollection::UpdatePanelCornerStyle(Panel
* panel
) {
724 panel::CornerStyle corner_style
;
725 bool at_top
= panel
== top_panel();
726 bool at_bottom
= panel
== bottom_panel();
727 if (at_top
&& at_bottom
)
728 corner_style
= panel::ALL_ROUNDED
;
730 corner_style
= panel::TOP_ROUNDED
;
732 corner_style
= panel::BOTTOM_ROUNDED
;
734 corner_style
= panel::NOT_ROUNDED
;
735 panel
->SetWindowCornerStyle(corner_style
);
738 gfx::Rect
StackedPanelCollection::GetWorkArea() const {
740 return panel_manager_
->display_settings_provider()->GetPrimaryWorkArea();
741 return panel_manager_
->display_settings_provider()->GetWorkAreaMatching(
742 GetEnclosingBounds());
745 int StackedPanelCollection::GetCurrentAvailableTopSpace() const {
746 gfx::Rect work_area
= GetWorkArea();
748 return work_area
.height();
750 int available_space
= top_panel()->GetBounds().y() - work_area
.y();
751 if (available_space
< 0)
753 return available_space
;
756 int StackedPanelCollection::GetCurrentAvailableBottomSpace() const {
757 gfx::Rect work_area
= GetWorkArea();
759 return work_area
.height();
761 int available_space
= work_area
.bottom() -
762 bottom_panel()->GetBounds().bottom();
763 if (available_space
< 0)
765 return available_space
;
768 int StackedPanelCollection::GetMaximiumAvailableBottomSpace() const {
769 gfx::Rect work_area
= GetWorkArea();
771 return work_area
.height();
773 int bottom
= top_panel()->GetBounds().y();
774 for (Panels::const_iterator iter
= panels_
.begin();
775 iter
!= panels_
.end(); iter
++) {
776 Panel
* panel
= *iter
;
777 // Only the most recently active panel might be active.
778 if (iter
== panels_
.begin() && panel
->IsActive())
779 bottom
+= panel
->GetBounds().height();
781 bottom
+= panel::kTitlebarHeight
;
783 int available_space
= work_area
.bottom() - bottom
;
784 if (available_space
< 0)
786 return available_space
;
789 NativePanelStackWindow
* StackedPanelCollection::GetStackWindowForPanel(
790 Panel
* panel
) const {
791 return secondary_stack_window_
&& secondary_stack_window_
->HasPanel(panel
) ?
792 secondary_stack_window_
: primary_stack_window_
;