Add a minor text member to ui::MenuModel.
[chromium-blink-merge.git] / chrome / browser / ui / panels / detached_panel_collection.cc
blobd525dac7cb7be195155688b34ec2aa00855c9224
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/detached_panel_collection.h"
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"
13 namespace {
14 // How much horizontal and vertical offset there is between newly opened
15 // detached panels.
16 const int kPanelTilePixels = 10;
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
25 DetachedPanelCollection::DetachedPanelCollection(PanelManager* panel_manager)
26 : PanelCollection(PanelCollection::DETACHED),
27 panel_manager_(panel_manager) {
30 DetachedPanelCollection::~DetachedPanelCollection() {
31 DCHECK(panels_.empty());
34 void DetachedPanelCollection::OnDisplayChanged() {
35 DisplaySettingsProvider* display_settings_provider =
36 panel_manager_->display_settings_provider();
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());
44 // Update size if needed.
45 panel->LimitSizeToWorkArea(work_area);
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());
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);
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);
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);
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();
95 void DetachedPanelCollection::RemovePanel(Panel* panel, RemovalReason reason) {
96 DCHECK_EQ(this, panel->collection());
97 panel->set_collection(NULL);
98 panels_.remove(panel);
101 void DetachedPanelCollection::CloseAll() {
102 // Make a copy as closing panels can modify the iterator.
103 Panels panels_copy = panels_;
105 for (Panels::const_iterator iter = panels_copy.begin();
106 iter != panels_copy.end(); ++iter)
107 (*iter)->Close();
110 void DetachedPanelCollection::OnPanelAttentionStateChanged(Panel* panel) {
111 DCHECK_EQ(this, panel->collection());
112 // Nothing to do.
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.
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());
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);
132 // Update restored size.
133 if (new_size != panel->full_size())
134 panel->set_full_size(new_size);
136 gfx::Rect bounds = panel->GetBounds();
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);
142 if (bounds != panel->GetBounds())
143 panel->SetPanelBounds(bounds);
146 void DetachedPanelCollection::ActivatePanel(Panel* panel) {
147 DCHECK_EQ(this, panel->collection());
148 // No change in panel's appearance.
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.
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.
163 void DetachedPanelCollection::OnMinimizeButtonClicked(
164 Panel* panel, panel::ClickModifier modifier) {
165 panel->MinimizeBySystem();
168 void DetachedPanelCollection::OnRestoreButtonClicked(
169 Panel* panel, panel::ClickModifier modifier) {
170 // No restore button is present.
171 NOTREACHED();
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();
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;
187 bool DetachedPanelCollection::IsPanelMinimized(const Panel* panel) const {
188 DCHECK_EQ(this, panel->collection());
189 // Detached panels do not minimize.
190 return false;
193 bool DetachedPanelCollection::UsesAlwaysOnTopPanels() const {
194 return false;
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();
203 void DetachedPanelCollection::RestorePanelToSavedPlacement() {
204 DCHECK(saved_panel_placement_.panel);
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);
210 DiscardSavedPanelPlacement();
213 void DetachedPanelCollection::DiscardSavedPanelPlacement() {
214 DCHECK(saved_panel_placement_.panel);
215 saved_panel_placement_.panel = NULL;
218 panel::Resizability DetachedPanelCollection::GetPanelResizability(
219 const Panel* panel) const {
220 return panel::RESIZABLE_ALL;
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());
229 bool DetachedPanelCollection::HasPanel(Panel* panel) const {
230 return std::find(panels_.begin(), panels_.end(), panel) != panels_.end();
233 void DetachedPanelCollection::SortPanels(PanelsComparer comparer) {
234 panels_.sort(comparer);
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->EnableResizeByMouse(true);
243 panel->UpdateMinimizeRestoreButtonVisibility();
244 panel->SetWindowCornerStyle(panel::ALL_ROUNDED);
247 void DetachedPanelCollection::OnPanelExpansionStateChanged(Panel* panel) {
248 // This should only be reached when a minimized stacked panel is dragged out
249 // of the stack to become detached. For this case, the panel needs to be
250 // restored.
251 DCHECK_EQ(Panel::EXPANDED, panel->expansion_state());
253 gfx::Rect bounds = panel->GetBounds();
254 bounds.set_height(panel->full_size().height());
255 panel->SetPanelBounds(bounds);
258 void DetachedPanelCollection::OnPanelActiveStateChanged(Panel* panel) {
261 gfx::Rect DetachedPanelCollection::GetInitialPanelBounds(
262 const gfx::Rect& requested_bounds) const {
263 if (!PanelManager::IsPanelStackingEnabled())
264 return requested_bounds;
266 gfx::Rect work_area = panel_manager_->display_settings_provider()->
267 GetWorkAreaMatching(requested_bounds);
268 gfx::Rect initial_bounds = requested_bounds;
269 initial_bounds.set_y(
270 work_area.y() + kDetachedPanelStartingYPositionOnStackingEnabled);
271 return initial_bounds;
274 gfx::Point DetachedPanelCollection::GetDefaultPanelOrigin() {
275 if (!default_panel_origin_.x() && !default_panel_origin_.y()) {
276 gfx::Rect work_area =
277 panel_manager_->display_settings_provider()->GetPrimaryWorkArea();
278 default_panel_origin_.SetPoint(kPanelTilePixels + work_area.x(),
279 kPanelTilePixels + work_area.y());
281 return default_panel_origin_;
284 void DetachedPanelCollection::ComputeNextDefaultPanelOrigin() {
285 default_panel_origin_.Offset(kPanelTilePixels, kPanelTilePixels);
286 gfx::Rect work_area =
287 panel_manager_->display_settings_provider()->GetPrimaryWorkArea();
288 if (!work_area.Contains(default_panel_origin_)) {
289 default_panel_origin_.SetPoint(kPanelTilePixels + work_area.x(),
290 kPanelTilePixels + work_area.y());