| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "chrome/browser/ui/panels/detached_panel_collection.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include "base/logging.h" | |
| 9 #include "chrome/browser/ui/panels/display_settings_provider.h" | |
| 10 #include "chrome/browser/ui/panels/panel_drag_controller.h" | |
| 11 #include "chrome/browser/ui/panels/panel_manager.h" | |
| 12 | |
| 13 namespace { | |
| 14 // How much horizontal and vertical offset there is between newly opened | |
| 15 // detached panels. | |
| 16 const int kPanelTilePixels = 10; | |
| 17 | |
| 18 // When the stacking mode is enabled, the detached panel will be positioned | |
| 19 // near the top of the working area such that the subsequent panel could be | |
| 20 // stacked to the bottom of the detached panel. This value is experimental | |
| 21 // and subjective. | |
| 22 const int kDetachedPanelStartingYPositionOnStackingEnabled = 20; | |
| 23 } // namespace | |
| 24 | |
| 25 DetachedPanelCollection::DetachedPanelCollection(PanelManager* panel_manager) | |
| 26 : PanelCollection(PanelCollection::DETACHED), | |
| 27 panel_manager_(panel_manager) { | |
| 28 } | |
| 29 | |
| 30 DetachedPanelCollection::~DetachedPanelCollection() { | |
| 31 DCHECK(panels_.empty()); | |
| 32 } | |
| 33 | |
| 34 void DetachedPanelCollection::OnDisplayChanged() { | |
| 35 DisplaySettingsProvider* display_settings_provider = | |
| 36 panel_manager_->display_settings_provider(); | |
| 37 | |
| 38 for (Panels::const_iterator iter = panels_.begin(); | |
| 39 iter != panels_.end(); ++iter) { | |
| 40 Panel* panel = *iter; | |
| 41 gfx::Rect work_area = | |
| 42 display_settings_provider->GetWorkAreaMatching(panel->GetBounds()); | |
| 43 | |
| 44 // Update size if needed. | |
| 45 panel->LimitSizeToWorkArea(work_area); | |
| 46 | |
| 47 // Update bounds to make sure the panel falls completely within the work | |
| 48 // area. Note that the origin of the work area might also change. | |
| 49 gfx::Rect bounds = panel->GetBounds(); | |
| 50 if (panel->full_size() != bounds.size()) { | |
| 51 bounds.set_size(panel->full_size()); | |
| 52 if (bounds.right() > work_area.right()) | |
| 53 bounds.set_x(work_area.right() - bounds.width()); | |
| 54 if (bounds.bottom() > work_area.bottom()) | |
| 55 bounds.set_y(work_area.bottom() - bounds.height()); | |
| 56 } | |
| 57 if (bounds.x() < work_area.x()) | |
| 58 bounds.set_x(work_area.x()); | |
| 59 if (bounds.y() < work_area.y()) | |
| 60 bounds.set_y(work_area.y()); | |
| 61 panel->SetPanelBoundsInstantly(bounds); | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 void DetachedPanelCollection::RefreshLayout() { | |
| 66 // A detached panel would still maintain its minimized state when it was | |
| 67 // moved out the stack and the drag has not ended. When the drag ends, it | |
| 68 // needs to be expanded. This could occur in the following scenarios: | |
| 69 // 1) It was originally a minimized panel that was dragged out of a stack. | |
| 70 // 2) It was originally a minimized panel that was the top panel in a stack. | |
| 71 // The panel below it was dragged out of the stack which also caused | |
| 72 // the top panel became detached. | |
| 73 for (Panels::const_iterator iter = panels_.begin(); | |
| 74 iter != panels_.end(); ++iter) { | |
| 75 Panel* panel = *iter; | |
| 76 if (!panel->in_preview_mode() && | |
| 77 panel->expansion_state() != Panel::EXPANDED) | |
| 78 panel->SetExpansionState(Panel::EXPANDED); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 void DetachedPanelCollection::AddPanel(Panel* panel, | |
| 83 PositioningMask positioning_mask) { | |
| 84 // positioning_mask is ignored since the detached panel is free-floating. | |
| 85 DCHECK_NE(this, panel->collection()); | |
| 86 panel->set_collection(this); | |
| 87 panels_.push_back(panel); | |
| 88 | |
| 89 // Offset the default position of the next detached panel if the current | |
| 90 // default position is used. | |
| 91 if (panel->GetBounds().origin() == default_panel_origin_) | |
| 92 ComputeNextDefaultPanelOrigin(); | |
| 93 } | |
| 94 | |
| 95 void DetachedPanelCollection::RemovePanel(Panel* panel, RemovalReason reason) { | |
| 96 DCHECK_EQ(this, panel->collection()); | |
| 97 panel->set_collection(NULL); | |
| 98 panels_.remove(panel); | |
| 99 } | |
| 100 | |
| 101 void DetachedPanelCollection::CloseAll() { | |
| 102 // Make a copy as closing panels can modify the iterator. | |
| 103 Panels panels_copy = panels_; | |
| 104 | |
| 105 for (Panels::const_iterator iter = panels_copy.begin(); | |
| 106 iter != panels_copy.end(); ++iter) | |
| 107 (*iter)->Close(); | |
| 108 } | |
| 109 | |
| 110 void DetachedPanelCollection::OnPanelAttentionStateChanged(Panel* panel) { | |
| 111 DCHECK_EQ(this, panel->collection()); | |
| 112 // Nothing to do. | |
| 113 } | |
| 114 | |
| 115 void DetachedPanelCollection::OnPanelTitlebarClicked(Panel* panel, | |
| 116 panel::ClickModifier modifier) { | |
| 117 DCHECK_EQ(this, panel->collection()); | |
| 118 // Click on detached panel titlebars does not do anything. | |
| 119 } | |
| 120 | |
| 121 void DetachedPanelCollection::ResizePanelWindow( | |
| 122 Panel* panel, | |
| 123 const gfx::Size& preferred_window_size) { | |
| 124 // We should get this call only of we have the panel. | |
| 125 DCHECK_EQ(this, panel->collection()); | |
| 126 | |
| 127 // Make sure the new size does not violate panel's size restrictions. | |
| 128 gfx::Size new_size(preferred_window_size.width(), | |
| 129 preferred_window_size.height()); | |
| 130 new_size = panel->ClampSize(new_size); | |
| 131 | |
| 132 // Update restored size. | |
| 133 if (new_size != panel->full_size()) | |
| 134 panel->set_full_size(new_size); | |
| 135 | |
| 136 gfx::Rect bounds = panel->GetBounds(); | |
| 137 | |
| 138 // When we resize a detached panel, its origin does not move. | |
| 139 // So we set height and width only. | |
| 140 bounds.set_size(new_size); | |
| 141 | |
| 142 if (bounds != panel->GetBounds()) | |
| 143 panel->SetPanelBounds(bounds); | |
| 144 } | |
| 145 | |
| 146 void DetachedPanelCollection::ActivatePanel(Panel* panel) { | |
| 147 DCHECK_EQ(this, panel->collection()); | |
| 148 // No change in panel's appearance. | |
| 149 } | |
| 150 | |
| 151 void DetachedPanelCollection::MinimizePanel(Panel* panel) { | |
| 152 DCHECK_EQ(this, panel->collection()); | |
| 153 // Detached panels do not minimize. However, extensions may call this API | |
| 154 // regardless of which collection the panel is in. So we just quietly return. | |
| 155 } | |
| 156 | |
| 157 void DetachedPanelCollection::RestorePanel(Panel* panel) { | |
| 158 DCHECK_EQ(this, panel->collection()); | |
| 159 // Detached panels do not minimize. However, extensions may call this API | |
| 160 // regardless of which collection the panel is in. So we just quietly return. | |
| 161 } | |
| 162 | |
| 163 void DetachedPanelCollection::OnMinimizeButtonClicked( | |
| 164 Panel* panel, panel::ClickModifier modifier) { | |
| 165 panel->MinimizeBySystem(); | |
| 166 } | |
| 167 | |
| 168 void DetachedPanelCollection::OnRestoreButtonClicked( | |
| 169 Panel* panel, panel::ClickModifier modifier) { | |
| 170 // No restore button is present. | |
| 171 NOTREACHED(); | |
| 172 } | |
| 173 | |
| 174 bool DetachedPanelCollection::CanShowMinimizeButton(const Panel* panel) const { | |
| 175 // We also show minimize button for detached panel when stacking mode is | |
| 176 // enabled. | |
| 177 return PanelManager::IsPanelStackingEnabled() && | |
| 178 PanelManager::CanUseSystemMinimize(); | |
| 179 } | |
| 180 | |
| 181 bool DetachedPanelCollection::CanShowRestoreButton(const Panel* panel) const { | |
| 182 // The minimize button is used for system minimize and thus there is no | |
| 183 // restore button. | |
| 184 return false; | |
| 185 } | |
| 186 | |
| 187 bool DetachedPanelCollection::IsPanelMinimized(const Panel* panel) const { | |
| 188 DCHECK_EQ(this, panel->collection()); | |
| 189 // Detached panels do not minimize. | |
| 190 return false; | |
| 191 } | |
| 192 | |
| 193 bool DetachedPanelCollection::UsesAlwaysOnTopPanels() const { | |
| 194 return false; | |
| 195 } | |
| 196 | |
| 197 void DetachedPanelCollection::SavePanelPlacement(Panel* panel) { | |
| 198 DCHECK(!saved_panel_placement_.panel); | |
| 199 saved_panel_placement_.panel = panel; | |
| 200 saved_panel_placement_.position = panel->GetBounds().origin(); | |
| 201 } | |
| 202 | |
| 203 void DetachedPanelCollection::RestorePanelToSavedPlacement() { | |
| 204 DCHECK(saved_panel_placement_.panel); | |
| 205 | |
| 206 gfx::Rect new_bounds(saved_panel_placement_.panel->GetBounds()); | |
| 207 new_bounds.set_origin(saved_panel_placement_.position); | |
| 208 saved_panel_placement_.panel->SetPanelBounds(new_bounds); | |
| 209 | |
| 210 DiscardSavedPanelPlacement(); | |
| 211 } | |
| 212 | |
| 213 void DetachedPanelCollection::DiscardSavedPanelPlacement() { | |
| 214 DCHECK(saved_panel_placement_.panel); | |
| 215 saved_panel_placement_.panel = NULL; | |
| 216 } | |
| 217 | |
| 218 panel::Resizability DetachedPanelCollection::GetPanelResizability( | |
| 219 const Panel* panel) const { | |
| 220 return panel::RESIZABLE_ALL; | |
| 221 } | |
| 222 | |
| 223 void DetachedPanelCollection::OnPanelResizedByMouse( | |
| 224 Panel* panel, const gfx::Rect& new_bounds) { | |
| 225 DCHECK_EQ(this, panel->collection()); | |
| 226 panel->set_full_size(new_bounds.size()); | |
| 227 } | |
| 228 | |
| 229 bool DetachedPanelCollection::HasPanel(Panel* panel) const { | |
| 230 return std::find(panels_.begin(), panels_.end(), panel) != panels_.end(); | |
| 231 } | |
| 232 | |
| 233 void DetachedPanelCollection::SortPanels(PanelsComparer comparer) { | |
| 234 panels_.sort(comparer); | |
| 235 } | |
| 236 | |
| 237 void DetachedPanelCollection::UpdatePanelOnCollectionChange(Panel* panel) { | |
| 238 panel->set_attention_mode( | |
| 239 static_cast<Panel::AttentionMode>(Panel::USE_PANEL_ATTENTION | | |
| 240 Panel::USE_SYSTEM_ATTENTION)); | |
| 241 panel->ShowShadow(true); | |
| 242 panel->UpdateMinimizeRestoreButtonVisibility(); | |
| 243 panel->SetWindowCornerStyle(panel::ALL_ROUNDED); | |
| 244 } | |
| 245 | |
| 246 void DetachedPanelCollection::OnPanelExpansionStateChanged(Panel* panel) { | |
| 247 // This should only be reached when a minimized stacked panel is dragged out | |
| 248 // of the stack to become detached. For this case, the panel needs to be | |
| 249 // restored. | |
| 250 DCHECK_EQ(Panel::EXPANDED, panel->expansion_state()); | |
| 251 | |
| 252 gfx::Rect bounds = panel->GetBounds(); | |
| 253 bounds.set_height(panel->full_size().height()); | |
| 254 panel->SetPanelBounds(bounds); | |
| 255 } | |
| 256 | |
| 257 void DetachedPanelCollection::OnPanelActiveStateChanged(Panel* panel) { | |
| 258 } | |
| 259 | |
| 260 gfx::Rect DetachedPanelCollection::GetInitialPanelBounds( | |
| 261 const gfx::Rect& requested_bounds) const { | |
| 262 if (!PanelManager::IsPanelStackingEnabled()) | |
| 263 return requested_bounds; | |
| 264 | |
| 265 gfx::Rect work_area = panel_manager_->display_settings_provider()-> | |
| 266 GetWorkAreaMatching(requested_bounds); | |
| 267 gfx::Rect initial_bounds = requested_bounds; | |
| 268 initial_bounds.set_y( | |
| 269 work_area.y() + kDetachedPanelStartingYPositionOnStackingEnabled); | |
| 270 return initial_bounds; | |
| 271 } | |
| 272 | |
| 273 gfx::Point DetachedPanelCollection::GetDefaultPanelOrigin() { | |
| 274 if (!default_panel_origin_.x() && !default_panel_origin_.y()) { | |
| 275 gfx::Rect work_area = | |
| 276 panel_manager_->display_settings_provider()->GetPrimaryWorkArea(); | |
| 277 default_panel_origin_.SetPoint(kPanelTilePixels + work_area.x(), | |
| 278 kPanelTilePixels + work_area.y()); | |
| 279 } | |
| 280 return default_panel_origin_; | |
| 281 } | |
| 282 | |
| 283 void DetachedPanelCollection::ComputeNextDefaultPanelOrigin() { | |
| 284 default_panel_origin_.Offset(kPanelTilePixels, kPanelTilePixels); | |
| 285 gfx::Rect work_area = | |
| 286 panel_manager_->display_settings_provider()->GetPrimaryWorkArea(); | |
| 287 if (!work_area.Contains(default_panel_origin_)) { | |
| 288 default_panel_origin_.SetPoint(kPanelTilePixels + work_area.x(), | |
| 289 kPanelTilePixels + work_area.y()); | |
| 290 } | |
| 291 } | |
| OLD | NEW |