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 |