| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/panels/docked_panel_strip.h" | 5 #include "chrome/browser/ui/panels/docked_panel_strip.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "chrome/browser/ui/browser.h" | 13 #include "chrome/browser/ui/browser.h" |
| 14 #include "chrome/browser/ui/panels/overflow_panel_strip.h" | |
| 15 #include "chrome/browser/ui/panels/panel_manager.h" | 14 #include "chrome/browser/ui/panels/panel_manager.h" |
| 16 #include "chrome/browser/ui/panels/panel_mouse_watcher.h" | 15 #include "chrome/browser/ui/panels/panel_mouse_watcher.h" |
| 17 #include "chrome/common/chrome_notification_types.h" | 16 #include "chrome/common/chrome_notification_types.h" |
| 18 #include "content/public/browser/notification_service.h" | 17 #include "content/public/browser/notification_service.h" |
| 19 #include "content/public/browser/notification_source.h" | 18 #include "content/public/browser/notification_source.h" |
| 20 | 19 |
| 21 namespace { | 20 namespace { |
| 22 // Width to height ratio is used to compute the default width or height | 21 // Width to height ratio is used to compute the default width or height |
| 23 // when only one value is provided. | 22 // when only one value is provided. |
| 24 const double kPanelDefaultWidthToHeightRatio = 1.62; // golden ratio | 23 const double kPanelDefaultWidthToHeightRatio = 1.62; // golden ratio |
| (...skipping 27 matching lines...) Expand all Loading... |
| 52 | 51 |
| 53 // static | 52 // static |
| 54 const int DockedPanelStrip::kPanelMinWidth = 100; | 53 const int DockedPanelStrip::kPanelMinWidth = 100; |
| 55 const int DockedPanelStrip::kPanelMinHeight = 20; | 54 const int DockedPanelStrip::kPanelMinHeight = 20; |
| 56 | 55 |
| 57 DockedPanelStrip::DockedPanelStrip(PanelManager* panel_manager) | 56 DockedPanelStrip::DockedPanelStrip(PanelManager* panel_manager) |
| 58 : PanelStrip(PanelStrip::DOCKED), | 57 : PanelStrip(PanelStrip::DOCKED), |
| 59 panel_manager_(panel_manager), | 58 panel_manager_(panel_manager), |
| 60 minimized_panel_count_(0), | 59 minimized_panel_count_(0), |
| 61 are_titlebars_up_(false), | 60 are_titlebars_up_(false), |
| 62 disable_layout_refresh_(false), | |
| 63 delayed_titlebar_action_(NO_ACTION), | 61 delayed_titlebar_action_(NO_ACTION), |
| 64 titlebar_action_factory_(this) { | 62 titlebar_action_factory_(this) { |
| 65 dragging_panel_current_iterator_ = dragging_panel_original_iterator_ = | 63 dragging_panel_current_iterator_ = dragging_panel_original_iterator_ = |
| 66 panels_.end(); | 64 panels_.end(); |
| 67 } | 65 } |
| 68 | 66 |
| 69 DockedPanelStrip::~DockedPanelStrip() { | 67 DockedPanelStrip::~DockedPanelStrip() { |
| 70 DCHECK(panels_.empty()); | 68 DCHECK(panels_.empty()); |
| 71 DCHECK(panels_in_temporary_layout_.empty()); | 69 DCHECK(panels_in_temporary_layout_.empty()); |
| 72 DCHECK_EQ(0, minimized_panel_count_); | 70 DCHECK_EQ(0, minimized_panel_count_); |
| 73 } | 71 } |
| 74 | 72 |
| 75 void DockedPanelStrip::SetDisplayArea(const gfx::Rect& display_area) { | 73 void DockedPanelStrip::SetDisplayArea(const gfx::Rect& display_area) { |
| 76 if (display_area_ == display_area) | 74 if (display_area_ == display_area) |
| 77 return; | 75 return; |
| 78 | 76 |
| 79 gfx::Rect old_area = display_area_; | 77 gfx::Rect old_area = display_area_; |
| 80 display_area_ = display_area; | 78 display_area_ = display_area; |
| 81 | 79 |
| 82 if (panels_.empty()) | 80 if (panels_.empty()) |
| 83 return; | 81 return; |
| 84 | 82 |
| 85 RefreshLayout(); | 83 RefreshLayout(); |
| 86 } | 84 } |
| 87 | 85 |
| 88 void DockedPanelStrip::AddPanel(Panel* panel) { | 86 void DockedPanelStrip::AddPanel(Panel* panel) { |
| 89 DCHECK_EQ(this, panel->panel_strip()); | 87 DCHECK_NE(this, panel->panel_strip()); |
| 88 panel->set_panel_strip(this); |
| 90 | 89 |
| 91 // Always update limits, even for exiting panels, in case the maximums changed | 90 // Always update limits, even on existing panels, in case the limits changed |
| 92 // while panel was out of the strip. | 91 // while panel was out of the strip. |
| 93 int max_panel_width = GetMaxPanelWidth(); | 92 int max_panel_width = GetMaxPanelWidth(); |
| 94 int max_panel_height = GetMaxPanelHeight(); | 93 int max_panel_height = GetMaxPanelHeight(); |
| 95 panel->SetSizeRange(gfx::Size(kPanelMinWidth, kPanelMinHeight), | 94 panel->SetSizeRange(gfx::Size(kPanelMinWidth, kPanelMinHeight), |
| 96 gfx::Size(max_panel_width, max_panel_height)); | 95 gfx::Size(max_panel_width, max_panel_height)); |
| 97 | 96 |
| 98 gfx::Size restored_size = panel->restored_size(); | 97 gfx::Size restored_size = panel->restored_size(); |
| 99 int height = restored_size.height(); | 98 int height = restored_size.height(); |
| 100 int width = restored_size.width(); | 99 int width = restored_size.width(); |
| 101 | 100 |
| 102 if (panel->initialized()) { | 101 if (panel->initialized()) { |
| 103 // Bump panels in the strip to make room for this panel. | 102 int x = FitPanelWithWidth(width); |
| 104 // Prevent layout refresh when panel is removed from this strip. | |
| 105 disable_layout_refresh_ = true; | |
| 106 PanelStrip* overflow_strip = panel_manager_->overflow_strip(); | |
| 107 int x; | |
| 108 while ((x = GetRightMostAvailablePosition() - width) < display_area_.x()) { | |
| 109 DCHECK(!panels_.empty()); | |
| 110 panels_.back()->MoveToStrip(overflow_strip); | |
| 111 } | |
| 112 disable_layout_refresh_ = false; | |
| 113 | 103 |
| 114 Panel::ExpansionState expansion_state_to_restore; | 104 Panel::ExpansionState expansion_state_to_restore; |
| 115 if (panel->expansion_state() == Panel::EXPANDED) { | 105 if (panel->expansion_state() == Panel::EXPANDED) { |
| 116 expansion_state_to_restore = Panel::EXPANDED; | 106 expansion_state_to_restore = Panel::EXPANDED; |
| 117 } else { | 107 } else { |
| 118 if (are_titlebars_up_ || panel->IsDrawingAttention()) { | 108 if (are_titlebars_up_ || panel->IsDrawingAttention()) { |
| 119 expansion_state_to_restore = Panel::TITLE_ONLY; | 109 expansion_state_to_restore = Panel::TITLE_ONLY; |
| 120 height = panel->TitleOnlyHeight(); | 110 height = panel->TitleOnlyHeight(); |
| 121 } else { | 111 } else { |
| 122 expansion_state_to_restore = Panel::MINIMIZED; | 112 expansion_state_to_restore = Panel::MINIMIZED; |
| 123 height = Panel::kMinimizedPanelHeight; | 113 height = Panel::kMinimizedPanelHeight; |
| 124 } | 114 } |
| 125 IncrementMinimizedPanels(); | 115 IncrementMinimizedPanels(); |
| 126 } | 116 } |
| 127 | |
| 128 int y = | 117 int y = |
| 129 GetBottomPositionForExpansionState(expansion_state_to_restore) - height; | 118 GetBottomPositionForExpansionState(expansion_state_to_restore) - height; |
| 130 panel->SetPanelBounds(gfx::Rect(x, y, width, height)); | 119 panel->SetPanelBounds(gfx::Rect(x, y, width, height)); |
| 131 | 120 |
| 132 // Update the minimized state to reflect current titlebar mode. | 121 // Update the minimized state to reflect current titlebar mode. |
| 133 // Do this AFTER setting panel bounds to avoid an extra bounds change. | 122 // Do this AFTER setting panel bounds to avoid an extra bounds change. |
| 134 if (panel->expansion_state() != Panel::EXPANDED) | 123 if (panel->expansion_state() != Panel::EXPANDED) |
| 135 panel->SetExpansionState(expansion_state_to_restore); | 124 panel->SetExpansionState(expansion_state_to_restore); |
| 136 | 125 |
| 137 } else { | 126 } else { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 | 185 |
| 197 int DockedPanelStrip::StartingRightPosition() const { | 186 int DockedPanelStrip::StartingRightPosition() const { |
| 198 return display_area_.right(); | 187 return display_area_.right(); |
| 199 } | 188 } |
| 200 | 189 |
| 201 int DockedPanelStrip::GetRightMostAvailablePosition() const { | 190 int DockedPanelStrip::GetRightMostAvailablePosition() const { |
| 202 return panels_.empty() ? StartingRightPosition() : | 191 return panels_.empty() ? StartingRightPosition() : |
| 203 (panels_.back()->GetBounds().x() - kPanelsHorizontalSpacing); | 192 (panels_.back()->GetBounds().x() - kPanelsHorizontalSpacing); |
| 204 } | 193 } |
| 205 | 194 |
| 206 bool DockedPanelStrip::RemovePanel(Panel* panel) { | 195 void DockedPanelStrip::RemovePanel(Panel* panel) { |
| 207 if (panel->has_temporary_layout()) { | 196 DCHECK_EQ(this, panel->panel_strip()); |
| 208 panels_in_temporary_layout_.erase(panel); | 197 panel->set_panel_strip(NULL); |
| 209 return true; | |
| 210 } | |
| 211 | |
| 212 Panels::iterator iter = find(panels_.begin(), panels_.end(), panel); | |
| 213 if (iter == panels_.end()) | |
| 214 return false; | |
| 215 | 198 |
| 216 if (panel->expansion_state() != Panel::EXPANDED) | 199 if (panel->expansion_state() != Panel::EXPANDED) |
| 217 DecrementMinimizedPanels(); | 200 DecrementMinimizedPanels(); |
| 218 | 201 |
| 219 // Removing an element from the list will invalidate the iterator that refers | 202 if (panel->has_temporary_layout()) { |
| 220 // to it. So we need to check if the dragging panel iterators are affected. | 203 panels_in_temporary_layout_.erase(panel); |
| 221 bool update_original_dragging_iterator_after_erase = false; | 204 return; |
| 222 if (dragging_panel_original_iterator_ != panels_.end()) { | |
| 223 if (dragging_panel_current_iterator_ == iter) { | |
| 224 // If the dragging panel is being removed, set both dragging iterators to | |
| 225 // the end of the list. | |
| 226 dragging_panel_current_iterator_ = dragging_panel_original_iterator_ = | |
| 227 panels_.end(); | |
| 228 } else if (dragging_panel_original_iterator_ == iter) { | |
| 229 // If |dragging_panel_original_iterator_| refers to the element being | |
| 230 // removed, set the flag so that the iterator can be updated to next | |
| 231 // element. | |
| 232 update_original_dragging_iterator_after_erase = true; | |
| 233 } | |
| 234 } | 205 } |
| 235 | 206 |
| 236 iter = panels_.erase(iter); | 207 // Removing an element from the list will invalidate the iterator that refers |
| 208 // to it. We need to update the iterator in that case. |
| 209 DCHECK(dragging_panel_current_iterator_ == panels_.end() || |
| 210 *dragging_panel_current_iterator_ != panel); |
| 211 bool update_iterator_after_erase = |
| 212 (dragging_panel_original_iterator_ != panels_.end() && |
| 213 *dragging_panel_original_iterator_ == panel); |
| 237 | 214 |
| 238 if (update_original_dragging_iterator_after_erase) | 215 // Optimize for the common case of removing the last panel. |
| 239 dragging_panel_original_iterator_ = iter; | 216 DCHECK(!panels_.empty()); |
| 240 | 217 if (panels_.back() == panel) { |
| 241 if (!disable_layout_refresh_) | 218 panels_.pop_back(); |
| 219 if (update_iterator_after_erase) |
| 220 dragging_panel_original_iterator_ = panels_.end(); |
| 221 // No need to refresh layout as the remaining panels are unaffected. |
| 222 // Just check if other panels can now fit in the freed up space. |
| 223 panel_manager_->MovePanelsOutOfOverflowIfCanFit(); |
| 224 } else { |
| 225 Panels::iterator iter = find(panels_.begin(), panels_.end(), panel); |
| 226 DCHECK(iter != panels_.end()); |
| 227 iter = panels_.erase(iter); |
| 228 if (update_iterator_after_erase) |
| 229 dragging_panel_original_iterator_ = iter; |
| 242 RefreshLayout(); | 230 RefreshLayout(); |
| 243 | 231 } |
| 244 return true; | |
| 245 } | 232 } |
| 246 | 233 |
| 247 bool DockedPanelStrip::CanShowPanelAsActive(const Panel* panel) const { | 234 bool DockedPanelStrip::CanShowPanelAsActive(const Panel* panel) const { |
| 248 // Panels with temporary layout cannot be shown as active. | 235 // Panels with temporary layout cannot be shown as active. |
| 249 return !panel->has_temporary_layout(); | 236 return !panel->has_temporary_layout(); |
| 250 } | 237 } |
| 251 | 238 |
| 252 bool DockedPanelStrip::CanDragPanel(const Panel* panel) const { | 239 bool DockedPanelStrip::CanDragPanel(const Panel* panel) const { |
| 253 // Only the panels having temporary layout can't be dragged. | 240 // Only the panels having temporary layout can't be dragged. |
| 254 return !panel->has_temporary_layout(); | 241 return !panel->has_temporary_layout(); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 | 423 |
| 437 panel->SetExpansionState(panel->IsDrawingAttention() ? | 424 panel->SetExpansionState(panel->IsDrawingAttention() ? |
| 438 Panel::TITLE_ONLY : Panel::MINIMIZED); | 425 Panel::TITLE_ONLY : Panel::MINIMIZED); |
| 439 } | 426 } |
| 440 | 427 |
| 441 void DockedPanelStrip::RestorePanel(Panel* panel) { | 428 void DockedPanelStrip::RestorePanel(Panel* panel) { |
| 442 DCHECK_EQ(this, panel->panel_strip()); | 429 DCHECK_EQ(this, panel->panel_strip()); |
| 443 panel->SetExpansionState(Panel::EXPANDED); | 430 panel->SetExpansionState(Panel::EXPANDED); |
| 444 } | 431 } |
| 445 | 432 |
| 433 bool DockedPanelStrip::IsPanelMinimized(const Panel* panel) const { |
| 434 return panel->expansion_state() != Panel::EXPANDED; |
| 435 } |
| 436 |
| 446 void DockedPanelStrip::IncrementMinimizedPanels() { | 437 void DockedPanelStrip::IncrementMinimizedPanels() { |
| 447 minimized_panel_count_++; | 438 minimized_panel_count_++; |
| 448 if (minimized_panel_count_ == 1) | 439 if (minimized_panel_count_ == 1) |
| 449 panel_manager_->mouse_watcher()->AddObserver(this); | 440 panel_manager_->mouse_watcher()->AddObserver(this); |
| 450 DCHECK_LE(minimized_panel_count_, num_panels()); | 441 DCHECK_LE(minimized_panel_count_, num_panels()); |
| 451 } | 442 } |
| 452 | 443 |
| 453 void DockedPanelStrip::DecrementMinimizedPanels() { | 444 void DockedPanelStrip::DecrementMinimizedPanels() { |
| 454 minimized_panel_count_--; | 445 minimized_panel_count_--; |
| 455 DCHECK_GE(minimized_panel_count_, 0); | 446 DCHECK_GE(minimized_panel_count_, 0); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 delayed_titlebar_action_ = NO_ACTION; | 663 delayed_titlebar_action_ = NO_ACTION; |
| 673 } | 664 } |
| 674 | 665 |
| 675 void DockedPanelStrip::OnFullScreenModeChanged(bool is_full_screen) { | 666 void DockedPanelStrip::OnFullScreenModeChanged(bool is_full_screen) { |
| 676 for (Panels::const_iterator iter = panels_.begin(); | 667 for (Panels::const_iterator iter = panels_.begin(); |
| 677 iter != panels_.end(); ++iter) { | 668 iter != panels_.end(); ++iter) { |
| 678 (*iter)->FullScreenModeChanged(is_full_screen); | 669 (*iter)->FullScreenModeChanged(is_full_screen); |
| 679 } | 670 } |
| 680 } | 671 } |
| 681 | 672 |
| 673 bool DockedPanelStrip::CanFitPanel(const Panel* panel) const { |
| 674 int width = panel->GetRestoredBounds().width(); |
| 675 return GetRightMostAvailablePosition() - width >= display_area_.x(); |
| 676 } |
| 677 |
| 678 int DockedPanelStrip::FitPanelWithWidth(int width) { |
| 679 int x = GetRightMostAvailablePosition() - width; |
| 680 if (x < display_area_.x()) { |
| 681 // Insufficient space for the requested width. Bump panels to overflow. |
| 682 Panel* last_panel_to_send_to_overflow; |
| 683 for (Panels::reverse_iterator iter = panels_.rbegin(); |
| 684 iter != panels_.rend(); ++iter) { |
| 685 last_panel_to_send_to_overflow = *iter; |
| 686 x = last_panel_to_send_to_overflow->GetRestoredBounds().right() - width; |
| 687 if (x >= display_area_.x()) { |
| 688 panel_manager_->MovePanelsToOverflow(last_panel_to_send_to_overflow); |
| 689 break; |
| 690 } |
| 691 } |
| 692 } |
| 693 return x; |
| 694 } |
| 695 |
| 682 void DockedPanelStrip::RefreshLayout() { | 696 void DockedPanelStrip::RefreshLayout() { |
| 683 int rightmost_position = StartingRightPosition(); | 697 int rightmost_position = StartingRightPosition(); |
| 684 | 698 |
| 685 Panels::const_iterator panel_iter = panels_.begin(); | 699 Panels::const_iterator panel_iter = panels_.begin(); |
| 686 for (; panel_iter != panels_.end(); ++panel_iter) { | 700 for (; panel_iter != panels_.end(); ++panel_iter) { |
| 687 Panel* panel = *panel_iter; | 701 Panel* panel = *panel_iter; |
| 688 gfx::Rect new_bounds(panel->GetBounds()); | 702 gfx::Rect new_bounds(panel->GetBounds()); |
| 689 int x = rightmost_position - new_bounds.width(); | 703 int x = rightmost_position - new_bounds.width(); |
| 690 | 704 |
| 691 if (x < display_area_.x()) | 705 if (x < display_area_.x()) |
| 692 break; | 706 break; |
| 693 | 707 |
| 694 // Don't update the docked panel that is currently dragged. | 708 // Don't update the docked panel that is currently dragged. |
| 695 if (panel != dragging_panel()) { | 709 if (panel != dragging_panel()) { |
| 696 new_bounds.set_x(x); | 710 new_bounds.set_x(x); |
| 697 new_bounds.set_y( | 711 new_bounds.set_y( |
| 698 GetBottomPositionForExpansionState(panel->expansion_state()) - | 712 GetBottomPositionForExpansionState(panel->expansion_state()) - |
| 699 new_bounds.height()); | 713 new_bounds.height()); |
| 700 panel->SetPanelBounds(new_bounds); | 714 panel->SetPanelBounds(new_bounds); |
| 701 } | 715 } |
| 702 | 716 |
| 703 rightmost_position = x - kPanelsHorizontalSpacing; | 717 rightmost_position = x - kPanelsHorizontalSpacing; |
| 704 } | 718 } |
| 705 | 719 |
| 706 // Add/remove panels from/to overflow. A change in work area or the | 720 // Add/remove panels from/to overflow. A change in work area or the |
| 707 // resize/removal of a panel may affect how many panels fit in the strip. | 721 // resize/removal of a panel may affect how many panels fit in the strip. |
| 708 OverflowPanelStrip* overflow_strip = panel_manager_->overflow_strip(); | 722 if (panel_iter != panels_.end()) |
| 709 if (panel_iter != panels_.end()) { | 723 panel_manager_->MovePanelsToOverflow(*panel_iter); |
| 710 // Prevent layout refresh when panel is removed from this strip. | 724 else |
| 711 disable_layout_refresh_ = true; | 725 panel_manager_->MovePanelsOutOfOverflowIfCanFit(); |
| 712 | |
| 713 // Keep track of panels to move to overflow in a separate storage since | |
| 714 // removing it from the list will invalidate the iterator. | |
| 715 std::vector<Panel*> panels_to_move_to_overflow; | |
| 716 for (; panel_iter != panels_.end(); ++panel_iter) | |
| 717 panels_to_move_to_overflow.push_back(*panel_iter); | |
| 718 | |
| 719 // Move panels to overflow in reverse to maintain their order. | |
| 720 for (std::vector<Panel*>::reverse_iterator iter = | |
| 721 panels_to_move_to_overflow.rbegin(); | |
| 722 iter != panels_to_move_to_overflow.rend(); ++iter) { | |
| 723 (*iter)->MoveToStrip(overflow_strip); | |
| 724 } | |
| 725 | |
| 726 disable_layout_refresh_ = false; | |
| 727 } else { | |
| 728 // Attempt to add more panels from overflow to the strip. | |
| 729 Panel* overflow_panel; | |
| 730 while ((overflow_panel = overflow_strip->first_panel()) && | |
| 731 GetRightMostAvailablePosition() >= | |
| 732 display_area_.x() + overflow_panel->restored_size().width()) { | |
| 733 overflow_panel->MoveToStrip(this); | |
| 734 } | |
| 735 } | |
| 736 } | 726 } |
| 737 | 727 |
| 738 void DockedPanelStrip::DelayedMovePanelToOverflow(Panel* panel) { | 728 void DockedPanelStrip::DelayedMovePanelToOverflow(Panel* panel) { |
| 739 if (panels_in_temporary_layout_.erase(panel)) { | 729 if (panels_in_temporary_layout_.erase(panel)) { |
| 740 DCHECK(panel->has_temporary_layout()); | 730 DCHECK(panel->has_temporary_layout()); |
| 741 panel->MoveToStrip(panel_manager_->overflow_strip()); | 731 panel_manager_->MovePanelToStrip(panel, PanelStrip::IN_OVERFLOW); |
| 742 } | 732 } |
| 743 } | 733 } |
| 744 | 734 |
| 745 void DockedPanelStrip::CloseAll() { | 735 void DockedPanelStrip::CloseAll() { |
| 746 // This should only be called at the end of tests to clean up. | 736 // This should only be called at the end of tests to clean up. |
| 747 DCHECK(panels_in_temporary_layout_.empty()); | 737 DCHECK(panels_in_temporary_layout_.empty()); |
| 748 | 738 |
| 749 // Make a copy of the iterator as closing panels can modify the vector. | 739 // Make a copy of the iterator as closing panels can modify the vector. |
| 750 Panels panels_copy = panels_; | 740 Panels panels_copy = panels_; |
| 751 | 741 |
| 752 // Start from the bottom to avoid reshuffling. | 742 // Start from the bottom to avoid reshuffling. |
| 753 for (Panels::reverse_iterator iter = panels_copy.rbegin(); | 743 for (Panels::reverse_iterator iter = panels_copy.rbegin(); |
| 754 iter != panels_copy.rend(); ++iter) | 744 iter != panels_copy.rend(); ++iter) |
| 755 (*iter)->Close(); | 745 (*iter)->Close(); |
| 756 } | 746 } |
| OLD | NEW |