| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/panel_manager.h" | 5 #include "chrome/browser/ui/panels/panel_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/logging.h" | 7 #include "base/logging.h" |
| 11 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/message_loop.h" | |
| 13 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" |
| 14 #include "chrome/browser/ui/browser_list.h" | 10 #include "chrome/browser/ui/browser_list.h" |
| 15 #include "chrome/browser/ui/panels/panel_mouse_watcher.h" | 11 #include "chrome/browser/ui/panels/panel_mouse_watcher.h" |
| 12 #include "chrome/browser/ui/panels/panel_strip.h" |
| 16 #include "chrome/browser/ui/window_sizer.h" | 13 #include "chrome/browser/ui/window_sizer.h" |
| 17 #include "chrome/common/chrome_notification_types.h" | 14 #include "chrome/common/chrome_notification_types.h" |
| 18 #include "content/public/browser/notification_service.h" | 15 #include "content/public/browser/notification_service.h" |
| 19 #include "content/public/browser/notification_source.h" | 16 #include "content/public/browser/notification_source.h" |
| 20 | 17 |
| 21 namespace { | 18 namespace { |
| 22 // Invalid panel index. | 19 const int kOverflowStripThickness = 24; |
| 23 const size_t kInvalidPanelIndex = static_cast<size_t>(-1); | |
| 24 | 20 |
| 25 // Width of spacing between first panel and the right edge of the screen. | 21 // Width of spacing around panel strip and the left/right edges of the screen. |
| 26 // Leaving a larger gap at the edge of the screen allows access to UI | 22 const int kPanelStripLeftMargin = kOverflowStripThickness + 6; |
| 27 // elements located on the bottom right of windows. | 23 const int kPanelStripRightMargin = 24; |
| 28 const int kRightScreenEdgeSpacingWidth = 24; | |
| 29 | 24 |
| 30 // Width to height ratio is used to compute the default width or height | 25 // Height of panel strip is based on the factor of the working area. |
| 31 // when only one value is provided. | 26 const double kPanelStripHeightFactor = 0.5; |
| 32 const double kPanelDefaultWidthToHeightRatio = 1.62; // golden ratio | |
| 33 | 27 |
| 34 // Maxmium width and height of a panel based on the factor of the working | |
| 35 // area. | |
| 36 const double kPanelMaxWidthFactor = 0.35; | |
| 37 const double kPanelMaxHeightFactor = 0.5; | |
| 38 | |
| 39 // Occasionally some system, like Windows, might not bring up or down the bottom | |
| 40 // bar when the mouse enters or leaves the bottom screen area. This is the | |
| 41 // maximum time we will wait for the bottom bar visibility change notification. | |
| 42 // After the time expires, we bring up/down the titlebars as planned. | |
| 43 const int kMaxMillisecondsWaitForBottomBarVisibilityChange = 1000; | |
| 44 | |
| 45 // See usage below. | |
| 46 #if defined(TOOLKIT_GTK) | |
| 47 const int kMillisecondsBeforeCollapsingFromTitleOnlyState = 2000; | |
| 48 #else | |
| 49 const int kMillisecondsBeforeCollapsingFromTitleOnlyState = 0; | |
| 50 #endif | |
| 51 } // namespace | 28 } // namespace |
| 52 | 29 |
| 53 // static | 30 // static |
| 54 const int PanelManager::kPanelMinWidth = 100; | |
| 55 const int PanelManager::kPanelMinHeight = 20; | |
| 56 | |
| 57 // static | |
| 58 PanelManager* PanelManager::GetInstance() { | 31 PanelManager* PanelManager::GetInstance() { |
| 59 static base::LazyInstance<PanelManager> instance = LAZY_INSTANCE_INITIALIZER; | 32 static base::LazyInstance<PanelManager> instance = LAZY_INSTANCE_INITIALIZER; |
| 60 return instance.Pointer(); | 33 return instance.Pointer(); |
| 61 } | 34 } |
| 62 | 35 |
| 63 PanelManager::PanelManager() | 36 PanelManager::PanelManager() |
| 64 : minimized_panel_count_(0), | 37 : panel_mouse_watcher_(PanelMouseWatcher::Create()), |
| 65 are_titlebars_up_(false), | 38 auto_sizing_enabled_(true) { |
| 66 dragging_panel_index_(kInvalidPanelIndex), | 39 panel_strip_.reset(new PanelStrip(this)); |
| 67 dragging_panel_original_x_(0), | |
| 68 delayed_titlebar_action_(NO_ACTION), | |
| 69 remove_delays_for_testing_(false), | |
| 70 titlebar_action_factory_(this), | |
| 71 auto_sizing_enabled_(true), | |
| 72 mouse_watching_disabled_(false) { | |
| 73 panel_mouse_watcher_.reset(PanelMouseWatcher::Create()); | |
| 74 auto_hiding_desktop_bar_ = AutoHidingDesktopBar::Create(this); | 40 auto_hiding_desktop_bar_ = AutoHidingDesktopBar::Create(this); |
| 75 OnDisplayChanged(); | 41 OnDisplayChanged(); |
| 76 } | 42 } |
| 77 | 43 |
| 78 PanelManager::~PanelManager() { | 44 PanelManager::~PanelManager() { |
| 79 DCHECK(panels_.empty()); | |
| 80 DCHECK(panels_pending_to_remove_.empty()); | |
| 81 DCHECK_EQ(0, minimized_panel_count_); | |
| 82 } | 45 } |
| 83 | 46 |
| 84 void PanelManager::OnDisplayChanged() { | 47 void PanelManager::OnDisplayChanged() { |
| 85 scoped_ptr<WindowSizer::MonitorInfoProvider> info_provider( | 48 scoped_ptr<WindowSizer::MonitorInfoProvider> info_provider( |
| 86 WindowSizer::CreateDefaultMonitorInfoProvider()); | 49 WindowSizer::CreateDefaultMonitorInfoProvider()); |
| 87 #if defined(OS_MACOSX) | 50 #if defined(OS_MACOSX) |
| 88 // On OSX, panels should be dropped all the way to the bottom edge of the | 51 // On OSX, panels should be dropped all the way to the bottom edge of the |
| 89 // screen (and overlap Dock). | 52 // screen (and overlap Dock). |
| 90 gfx::Rect work_area = info_provider->GetPrimaryMonitorBounds(); | 53 gfx::Rect work_area = info_provider->GetPrimaryMonitorBounds(); |
| 91 #else | 54 #else |
| 92 gfx::Rect work_area = info_provider->GetPrimaryMonitorWorkArea(); | 55 gfx::Rect work_area = info_provider->GetPrimaryMonitorWorkArea(); |
| 93 #endif | 56 #endif |
| 94 SetWorkArea(work_area); | 57 SetWorkArea(work_area); |
| 95 } | 58 } |
| 96 | 59 |
| 97 void PanelManager::SetWorkArea(const gfx::Rect& work_area) { | 60 void PanelManager::SetWorkArea(const gfx::Rect& work_area) { |
| 98 if (work_area == work_area_) | 61 if (work_area == work_area_) |
| 99 return; | 62 return; |
| 100 work_area_ = work_area; | 63 work_area_ = work_area; |
| 101 | 64 |
| 102 auto_hiding_desktop_bar_->UpdateWorkArea(work_area_); | 65 auto_hiding_desktop_bar_->UpdateWorkArea(work_area_); |
| 103 AdjustWorkAreaForAutoHidingDesktopBars(); | 66 AdjustWorkAreaForAutoHidingDesktopBars(); |
| 67 Layout(); |
| 68 } |
| 104 | 69 |
| 105 Rearrange(panels_.begin(), StartingRightPosition()); | 70 void PanelManager::Layout() { |
| 71 int height = |
| 72 static_cast<int>(adjusted_work_area_.height() * kPanelStripHeightFactor); |
| 73 gfx::Rect panel_strip_bounds; |
| 74 panel_strip_bounds.set_x(adjusted_work_area_.x() + kPanelStripLeftMargin); |
| 75 panel_strip_bounds.set_y(adjusted_work_area_.bottom() - height); |
| 76 panel_strip_bounds.set_width(adjusted_work_area_.width() - |
| 77 kPanelStripLeftMargin - kPanelStripRightMargin); |
| 78 panel_strip_bounds.set_height(height); |
| 79 panel_strip_->SetBounds(panel_strip_bounds); |
| 106 } | 80 } |
| 107 | 81 |
| 108 Panel* PanelManager::CreatePanel(Browser* browser) { | 82 Panel* PanelManager::CreatePanel(Browser* browser) { |
| 109 int width = browser->override_bounds().width(); | 83 int width = browser->override_bounds().width(); |
| 110 int height = browser->override_bounds().height(); | 84 int height = browser->override_bounds().height(); |
| 111 | |
| 112 Panel* panel = new Panel(browser, gfx::Size(width, height)); | 85 Panel* panel = new Panel(browser, gfx::Size(width, height)); |
| 113 | 86 panel_strip_->AddPanel(panel); |
| 114 int max_panel_width = GetMaxPanelWidth(); | |
| 115 int max_panel_height = GetMaxPanelHeight(); | |
| 116 panel->SetSizeRange(gfx::Size(kPanelMinWidth, kPanelMinHeight), | |
| 117 gfx::Size(max_panel_width, max_panel_height)); | |
| 118 | |
| 119 // Auto resizable is enabled only if no initial size is provided. | |
| 120 bool auto_resize = (width == 0 && height == 0); | |
| 121 panel->SetAutoResizable(auto_resize); | |
| 122 | |
| 123 // Adjust the width and height to fit into our constraint. | |
| 124 if (!auto_resize) { | |
| 125 if (height == 0) | |
| 126 height = width / kPanelDefaultWidthToHeightRatio; | |
| 127 if (width == 0) | |
| 128 width = height * kPanelDefaultWidthToHeightRatio; | |
| 129 } | |
| 130 | |
| 131 if (width < kPanelMinWidth) | |
| 132 width = kPanelMinWidth; | |
| 133 else if (width > max_panel_width) | |
| 134 width = max_panel_width; | |
| 135 | |
| 136 if (height < kPanelMinHeight) | |
| 137 height = kPanelMinHeight; | |
| 138 else if (height > max_panel_height) | |
| 139 height = max_panel_height; | |
| 140 | |
| 141 panel->set_restored_size(gfx::Size(width, height)); | |
| 142 | |
| 143 // Layout the new panel. | |
| 144 int y = adjusted_work_area_.bottom() - height; | |
| 145 int x = GetRightMostAvailablePosition() - width; | |
| 146 panel->Initialize(gfx::Rect(x, y, width, height)); | |
| 147 | |
| 148 panels_.push_back(panel); | |
| 149 | 87 |
| 150 content::NotificationService::current()->Notify( | 88 content::NotificationService::current()->Notify( |
| 151 chrome::NOTIFICATION_PANEL_ADDED, | 89 chrome::NOTIFICATION_PANEL_ADDED, |
| 152 content::Source<Panel>(panel), | 90 content::Source<Panel>(panel), |
| 153 content::NotificationService::NoDetails()); | 91 content::NotificationService::NoDetails()); |
| 154 | 92 |
| 155 return panel; | 93 return panel; |
| 156 } | 94 } |
| 157 | 95 |
| 158 int PanelManager::GetMaxPanelWidth() const { | |
| 159 return static_cast<int>(adjusted_work_area_.width() * kPanelMaxWidthFactor); | |
| 160 } | |
| 161 | |
| 162 int PanelManager::GetMaxPanelHeight() const { | |
| 163 return static_cast<int>(adjusted_work_area_.height() * kPanelMaxHeightFactor); | |
| 164 } | |
| 165 | |
| 166 int PanelManager::StartingRightPosition() const { | 96 int PanelManager::StartingRightPosition() const { |
| 167 return adjusted_work_area_.right() - kRightScreenEdgeSpacingWidth; | 97 return panel_strip_->StartingRightPosition(); |
| 168 } | |
| 169 | |
| 170 int PanelManager::GetRightMostAvailablePosition() const { | |
| 171 return panels_.empty() ? StartingRightPosition() : | |
| 172 (panels_.back()->GetBounds().x() - kPanelsHorizontalSpacing); | |
| 173 } | 98 } |
| 174 | 99 |
| 175 void PanelManager::Remove(Panel* panel) { | 100 void PanelManager::Remove(Panel* panel) { |
| 176 // If we're in the process of dragging, delay the removal. | 101 if (panel_strip_->Remove(panel)) |
| 177 if (dragging_panel_index_ != kInvalidPanelIndex) { | |
| 178 panels_pending_to_remove_.push_back(panel); | |
| 179 return; | 102 return; |
| 180 } | 103 // TODO(jianli): else try removing from overflow strip |
| 181 | |
| 182 DoRemove(panel); | |
| 183 } | 104 } |
| 184 | 105 |
| 185 void PanelManager::DelayedRemove() { | 106 void PanelManager::OnPanelRemoved(Panel* panel) { |
| 186 for (size_t i = 0; i < panels_pending_to_remove_.size(); ++i) | |
| 187 DoRemove(panels_pending_to_remove_[i]); | |
| 188 panels_pending_to_remove_.clear(); | |
| 189 } | |
| 190 | |
| 191 void PanelManager::DoRemove(Panel* panel) { | |
| 192 Panels::iterator iter = find(panels_.begin(), panels_.end(), panel); | |
| 193 if (iter == panels_.end()) | |
| 194 return; | |
| 195 | |
| 196 if (panel->expansion_state() != Panel::EXPANDED) | |
| 197 DecrementMinimizedPanels(); | |
| 198 | |
| 199 gfx::Rect bounds = (*iter)->GetBounds(); | |
| 200 Rearrange(panels_.erase(iter), bounds.right()); | |
| 201 | |
| 202 content::NotificationService::current()->Notify( | 107 content::NotificationService::current()->Notify( |
| 203 chrome::NOTIFICATION_PANEL_REMOVED, | 108 chrome::NOTIFICATION_PANEL_REMOVED, |
| 204 content::Source<Panel>(panel), | 109 content::Source<Panel>(panel), |
| 205 content::NotificationService::NoDetails()); | 110 content::NotificationService::NoDetails()); |
| 206 } | 111 } |
| 207 | 112 |
| 208 void PanelManager::StartDragging(Panel* panel) { | 113 void PanelManager::StartDragging(Panel* panel) { |
| 209 for (size_t i = 0; i < panels_.size(); ++i) { | 114 panel_strip_->StartDragging(panel); |
| 210 if (panels_[i] == panel) { | |
| 211 dragging_panel_index_ = i; | |
| 212 dragging_panel_bounds_ = panel->GetBounds(); | |
| 213 dragging_panel_original_x_ = dragging_panel_bounds_.x(); | |
| 214 break; | |
| 215 } | |
| 216 } | |
| 217 } | 115 } |
| 218 | 116 |
| 219 void PanelManager::Drag(int delta_x) { | 117 void PanelManager::Drag(int delta_x) { |
| 220 DCHECK(dragging_panel_index_ != kInvalidPanelIndex); | 118 panel_strip_->Drag(delta_x); |
| 221 | |
| 222 if (!delta_x) | |
| 223 return; | |
| 224 | |
| 225 // Moves this panel to the dragging position. | |
| 226 Panel* dragging_panel = panels_[dragging_panel_index_]; | |
| 227 gfx::Rect new_bounds(dragging_panel->GetBounds()); | |
| 228 new_bounds.set_x(new_bounds.x() + delta_x); | |
| 229 dragging_panel->SetPanelBounds(new_bounds); | |
| 230 | |
| 231 // Checks and processes other affected panels. | |
| 232 if (delta_x > 0) | |
| 233 DragRight(); | |
| 234 else | |
| 235 DragLeft(); | |
| 236 } | |
| 237 | |
| 238 void PanelManager::DragLeft() { | |
| 239 Panel* dragging_panel = panels_[dragging_panel_index_]; | |
| 240 | |
| 241 // This is the left corner of the dragging panel. We use it to check against | |
| 242 // all the panels on its left. | |
| 243 int dragging_panel_left_boundary = dragging_panel->GetBounds().x(); | |
| 244 | |
| 245 // This is the right corner which a panel will be moved to. | |
| 246 int current_panel_right_boundary = | |
| 247 dragging_panel_bounds_.x() + dragging_panel_bounds_.width(); | |
| 248 | |
| 249 // Checks the panels to the left of the dragging panel. | |
| 250 size_t current_panel_index = dragging_panel_index_ + 1; | |
| 251 for (; current_panel_index < panels_.size(); ++current_panel_index) { | |
| 252 Panel* current_panel = panels_[current_panel_index]; | |
| 253 | |
| 254 // Current panel will only be affected if the left corner of dragging | |
| 255 // panel goes beyond the middle position of the current panel. | |
| 256 if (dragging_panel_left_boundary > current_panel->GetBounds().x() + | |
| 257 current_panel->GetBounds().width() / 2) | |
| 258 break; | |
| 259 | |
| 260 // Moves current panel to the new position. | |
| 261 gfx::Rect bounds(current_panel->GetBounds()); | |
| 262 bounds.set_x(current_panel_right_boundary - bounds.width()); | |
| 263 current_panel_right_boundary -= bounds.width() + kPanelsHorizontalSpacing; | |
| 264 current_panel->SetPanelBounds(bounds); | |
| 265 | |
| 266 // Updates the index of current panel since it has been moved to the | |
| 267 // position of previous panel. | |
| 268 panels_[current_panel_index - 1] = current_panel; | |
| 269 } | |
| 270 | |
| 271 // Updates the position and index of dragging panel as the result of moving | |
| 272 // other affected panels. | |
| 273 if (current_panel_index != dragging_panel_index_ + 1) { | |
| 274 dragging_panel_bounds_.set_x(current_panel_right_boundary - | |
| 275 dragging_panel_bounds_.width()); | |
| 276 dragging_panel_index_ = current_panel_index - 1; | |
| 277 panels_[dragging_panel_index_] = dragging_panel; | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 void PanelManager::DragRight() { | |
| 282 Panel* dragging_panel = panels_[dragging_panel_index_]; | |
| 283 | |
| 284 // This is the right corner of the dragging panel. We use it to check against | |
| 285 // all the panels on its right. | |
| 286 int dragging_panel_right_boundary = dragging_panel->GetBounds().x() + | |
| 287 dragging_panel->GetBounds().width() - 1; | |
| 288 | |
| 289 // This is the left corner which a panel will be moved to. | |
| 290 int current_panel_left_boundary = dragging_panel_bounds_.x(); | |
| 291 | |
| 292 // Checks the panels to the right of the dragging panel. | |
| 293 int current_panel_index = static_cast<int>(dragging_panel_index_) - 1; | |
| 294 for (; current_panel_index >= 0; --current_panel_index) { | |
| 295 Panel* current_panel = panels_[current_panel_index]; | |
| 296 | |
| 297 // Current panel will only be affected if the right corner of dragging | |
| 298 // panel goes beyond the middle position of the current panel. | |
| 299 if (dragging_panel_right_boundary < current_panel->GetBounds().x() + | |
| 300 current_panel->GetBounds().width() / 2) | |
| 301 break; | |
| 302 | |
| 303 // Moves current panel to the new position. | |
| 304 gfx::Rect bounds(current_panel->GetBounds()); | |
| 305 bounds.set_x(current_panel_left_boundary); | |
| 306 current_panel_left_boundary += bounds.width() + kPanelsHorizontalSpacing; | |
| 307 current_panel->SetPanelBounds(bounds); | |
| 308 | |
| 309 // Updates the index of current panel since it has been moved to the | |
| 310 // position of previous panel. | |
| 311 panels_[current_panel_index + 1] = current_panel; | |
| 312 } | |
| 313 | |
| 314 // Updates the position and index of dragging panel as the result of moving | |
| 315 // other affected panels. | |
| 316 if (current_panel_index != static_cast<int>(dragging_panel_index_) - 1) { | |
| 317 dragging_panel_bounds_.set_x(current_panel_left_boundary); | |
| 318 dragging_panel_index_ = current_panel_index + 1; | |
| 319 panels_[dragging_panel_index_] = dragging_panel; | |
| 320 } | |
| 321 } | 119 } |
| 322 | 120 |
| 323 void PanelManager::EndDragging(bool cancelled) { | 121 void PanelManager::EndDragging(bool cancelled) { |
| 324 DCHECK(dragging_panel_index_ != kInvalidPanelIndex); | 122 panel_strip_->EndDragging(cancelled); |
| 325 | |
| 326 if (cancelled) { | |
| 327 Drag(dragging_panel_original_x_ - | |
| 328 panels_[dragging_panel_index_]->GetBounds().x()); | |
| 329 } else { | |
| 330 panels_[dragging_panel_index_]->SetPanelBounds( | |
| 331 dragging_panel_bounds_); | |
| 332 } | |
| 333 | |
| 334 dragging_panel_index_ = kInvalidPanelIndex; | |
| 335 | |
| 336 DelayedRemove(); | |
| 337 } | 123 } |
| 338 | 124 |
| 339 void PanelManager::OnPanelExpansionStateChanged( | 125 void PanelManager::OnPanelExpansionStateChanged( |
| 340 Panel::ExpansionState old_state, Panel::ExpansionState new_state) { | 126 Panel::ExpansionState old_state, Panel::ExpansionState new_state) { |
| 341 DCHECK_NE(new_state, old_state); | 127 panel_strip_->OnPanelExpansionStateChanged(old_state, new_state); |
| 342 switch (new_state) { | |
| 343 case Panel::EXPANDED: | |
| 344 DecrementMinimizedPanels(); | |
| 345 break; | |
| 346 case Panel::MINIMIZED: | |
| 347 case Panel::TITLE_ONLY: | |
| 348 if (old_state == Panel::EXPANDED) | |
| 349 IncrementMinimizedPanels(); | |
| 350 break; | |
| 351 default: | |
| 352 break; | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 void PanelManager::IncrementMinimizedPanels() { | |
| 357 if (!mouse_watching_disabled_ && !minimized_panel_count_) | |
| 358 panel_mouse_watcher_->AddObserver(this); | |
| 359 minimized_panel_count_++; | |
| 360 DCHECK_LE(minimized_panel_count_, num_panels()); | |
| 361 } | |
| 362 | |
| 363 void PanelManager::DecrementMinimizedPanels() { | |
| 364 minimized_panel_count_--; | |
| 365 DCHECK_GE(minimized_panel_count_, 0); | |
| 366 if (!mouse_watching_disabled_ && !minimized_panel_count_) | |
| 367 panel_mouse_watcher_->RemoveObserver(this); | |
| 368 } | 128 } |
| 369 | 129 |
| 370 void PanelManager::OnPreferredWindowSizeChanged( | 130 void PanelManager::OnPreferredWindowSizeChanged( |
| 371 Panel* panel, const gfx::Size& preferred_window_size) { | 131 Panel* panel, const gfx::Size& preferred_window_size) { |
| 372 if (!auto_sizing_enabled_) | 132 if (!auto_sizing_enabled_) |
| 373 return; | 133 return; |
| 374 | 134 panel_strip_->OnPreferredWindowSizeChanged(panel, preferred_window_size); |
| 375 gfx::Rect bounds = panel->GetBounds(); | |
| 376 | |
| 377 // The panel width: | |
| 378 // * cannot grow or shrink to go beyond [min_width, max_width] | |
| 379 int new_width = preferred_window_size.width(); | |
| 380 if (new_width > panel->max_size().width()) | |
| 381 new_width = panel->max_size().width(); | |
| 382 if (new_width < panel->min_size().width()) | |
| 383 new_width = panel->min_size().width(); | |
| 384 | |
| 385 if (new_width != bounds.width()) { | |
| 386 int delta = bounds.width() - new_width; | |
| 387 bounds.set_x(bounds.x() + delta); | |
| 388 bounds.set_width(new_width); | |
| 389 | |
| 390 // Reposition all the panels on the left. | |
| 391 int panel_index = -1; | |
| 392 for (int i = 0; i < static_cast<int>(panels_.size()); ++i) { | |
| 393 if (panels_[i] == panel) { | |
| 394 panel_index = i; | |
| 395 break; | |
| 396 } | |
| 397 } | |
| 398 DCHECK(panel_index >= 0); | |
| 399 for (int i = static_cast<int>(panels_.size()) -1; i > panel_index; | |
| 400 --i) { | |
| 401 gfx::Rect this_bounds = panels_[i]->GetBounds(); | |
| 402 this_bounds.set_x(this_bounds.x() + delta); | |
| 403 panels_[i]->SetPanelBounds(this_bounds); | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 // The panel height: | |
| 408 // * cannot grow or shrink to go beyond [min_height, max_height] | |
| 409 int new_height = preferred_window_size.height(); | |
| 410 if (new_height > panel->max_size().height()) | |
| 411 new_height = panel->max_size().height(); | |
| 412 if (new_height < panel->min_size().height()) | |
| 413 new_height = panel->min_size().height(); | |
| 414 | |
| 415 // Only need to adjust bounds height when panel is expanded. | |
| 416 gfx::Size restored_size = panel->restored_size(); | |
| 417 if (new_height != restored_size.height() && | |
| 418 panel->expansion_state() == Panel::EXPANDED) { | |
| 419 bounds.set_y(bounds.y() - new_height + bounds.height()); | |
| 420 bounds.set_height(new_height); | |
| 421 } | |
| 422 | |
| 423 gfx::Size new_size = gfx::Size(new_width, new_height); | |
| 424 if (new_size != restored_size) | |
| 425 panel->set_restored_size(new_size); | |
| 426 | |
| 427 panel->SetPanelBounds(bounds); | |
| 428 } | 135 } |
| 429 | 136 |
| 430 bool PanelManager::ShouldBringUpTitlebars(int mouse_x, int mouse_y) const { | 137 bool PanelManager::ShouldBringUpTitlebars(int mouse_x, int mouse_y) const { |
| 431 // We should always bring up the titlebar if the mouse is over the | 138 return panel_strip_->ShouldBringUpTitlebars(mouse_x, mouse_y); |
| 432 // visible auto-hiding bottom bar. | |
| 433 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM) && | |
| 434 auto_hiding_desktop_bar_->GetVisibility( | |
| 435 AutoHidingDesktopBar::ALIGN_BOTTOM) == | |
| 436 AutoHidingDesktopBar::VISIBLE && | |
| 437 mouse_y >= adjusted_work_area_.bottom()) | |
| 438 return true; | |
| 439 | |
| 440 for (Panels::const_iterator iter = panels_.begin(); | |
| 441 iter != panels_.end(); ++iter) { | |
| 442 if ((*iter)->ShouldBringUpTitlebar(mouse_x, mouse_y)) | |
| 443 return true; | |
| 444 } | |
| 445 return false; | |
| 446 } | 139 } |
| 447 | 140 |
| 448 void PanelManager::BringUpOrDownTitlebars(bool bring_up) { | 141 void PanelManager::BringUpOrDownTitlebars(bool bring_up) { |
| 449 if (are_titlebars_up_ == bring_up) | 142 panel_strip_->BringUpOrDownTitlebars(bring_up); |
| 450 return; | |
| 451 are_titlebars_up_ = bring_up; | |
| 452 | |
| 453 int task_delay_milliseconds = 0; | |
| 454 | |
| 455 // If the auto-hiding bottom bar exists, delay the action until the bottom | |
| 456 // bar is fully visible or hidden. We do not want both bottom bar and panel | |
| 457 // titlebar to move at the same time but with different speeds. | |
| 458 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM)) { | |
| 459 AutoHidingDesktopBar::Visibility visibility = auto_hiding_desktop_bar_-> | |
| 460 GetVisibility(AutoHidingDesktopBar::ALIGN_BOTTOM); | |
| 461 if (visibility != (bring_up ? AutoHidingDesktopBar::VISIBLE | |
| 462 : AutoHidingDesktopBar::HIDDEN)) { | |
| 463 // Occasionally some system, like Windows, might not bring up or down the | |
| 464 // bottom bar when the mouse enters or leaves the bottom screen area. | |
| 465 // Thus, we schedule a delayed task to do the work if we do not receive | |
| 466 // the bottom bar visibility change notification within a certain period | |
| 467 // of time. | |
| 468 task_delay_milliseconds = | |
| 469 kMaxMillisecondsWaitForBottomBarVisibilityChange; | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 // On some OSes, the interaction with native Taskbars/Docks may be improved | |
| 474 // if the panels do not go back to minimized state too fast. For example, | |
| 475 // it makes it possible to hit the titlebar on OSX if Dock has Magnifying | |
| 476 // enabled - the panels stay up for a while after Dock magnification effect | |
| 477 // stops covering the panels. | |
| 478 // | |
| 479 // Another example would be taskbar in auto-hide mode on Linux. In this mode | |
| 480 // taskbar will cover the panel in title hover mode, leaving it up for a few | |
| 481 // seconds would allow the user to be able to click on it. | |
| 482 // | |
| 483 // Currently, no platforms use both delays. | |
| 484 DCHECK(task_delay_milliseconds == 0); | |
| 485 if (!bring_up) | |
| 486 task_delay_milliseconds = kMillisecondsBeforeCollapsingFromTitleOnlyState; | |
| 487 | |
| 488 // OnAutoHidingDesktopBarVisibilityChanged will handle this. | |
| 489 delayed_titlebar_action_ = bring_up ? BRING_UP : BRING_DOWN; | |
| 490 if (remove_delays_for_testing_) | |
| 491 task_delay_milliseconds = 0; | |
| 492 | |
| 493 // If user moves the mouse in and out of mouse tracking area, we might have | |
| 494 // previously posted but not yet dispatched task in the queue. New action | |
| 495 // should always 'reset' the delays so cancel any tasks that haven't run yet | |
| 496 // and post a new one. | |
| 497 titlebar_action_factory_.InvalidateWeakPtrs(); | |
| 498 MessageLoop::current()->PostDelayedTask( | |
| 499 FROM_HERE, | |
| 500 base::Bind(&PanelManager::DelayedBringUpOrDownTitlebarsCheck, | |
| 501 titlebar_action_factory_.GetWeakPtr()), | |
| 502 task_delay_milliseconds); | |
| 503 } | |
| 504 | |
| 505 void PanelManager::DelayedBringUpOrDownTitlebarsCheck() { | |
| 506 // Task was already processed or cancelled - bail out. | |
| 507 if (delayed_titlebar_action_ == NO_ACTION) | |
| 508 return; | |
| 509 | |
| 510 bool need_to_bring_up_titlebars = (delayed_titlebar_action_ == BRING_UP); | |
| 511 | |
| 512 delayed_titlebar_action_ = NO_ACTION; | |
| 513 | |
| 514 // Check if the action is still needed based on the latest mouse position. The | |
| 515 // user could move the mouse into the tracking area and then quickly move it | |
| 516 // out of the area. In case of this, cancel the action. | |
| 517 if (are_titlebars_up_ != need_to_bring_up_titlebars) | |
| 518 return; | |
| 519 | |
| 520 DoBringUpOrDownTitlebars(need_to_bring_up_titlebars); | |
| 521 } | |
| 522 | |
| 523 void PanelManager::DoBringUpOrDownTitlebars(bool bring_up) { | |
| 524 for (Panels::const_iterator iter = panels_.begin(); | |
| 525 iter != panels_.end(); ++iter) { | |
| 526 Panel* panel = *iter; | |
| 527 | |
| 528 // Skip any panel that is drawing the attention. | |
| 529 if (panel->IsDrawingAttention()) | |
| 530 continue; | |
| 531 | |
| 532 if (bring_up) { | |
| 533 if (panel->expansion_state() == Panel::MINIMIZED) | |
| 534 panel->SetExpansionState(Panel::TITLE_ONLY); | |
| 535 } else { | |
| 536 if (panel->expansion_state() == Panel::TITLE_ONLY) | |
| 537 panel->SetExpansionState(Panel::MINIMIZED); | |
| 538 } | |
| 539 } | |
| 540 } | 143 } |
| 541 | 144 |
| 542 void PanelManager::AdjustWorkAreaForAutoHidingDesktopBars() { | 145 void PanelManager::AdjustWorkAreaForAutoHidingDesktopBars() { |
| 543 // Note that we do not care about the desktop bar aligned to the top edge | 146 // Note that we do not care about the desktop bar aligned to the top edge |
| 544 // since panels could not reach so high due to size constraint. | 147 // since panels could not reach so high due to size constraint. |
| 545 adjusted_work_area_ = work_area_; | 148 adjusted_work_area_ = work_area_; |
| 546 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_LEFT)) { | 149 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_LEFT)) { |
| 547 int space = auto_hiding_desktop_bar_->GetThickness( | 150 int space = auto_hiding_desktop_bar_->GetThickness( |
| 548 AutoHidingDesktopBar::ALIGN_LEFT); | 151 AutoHidingDesktopBar::ALIGN_LEFT); |
| 549 adjusted_work_area_.set_x(adjusted_work_area_.x() + space); | 152 adjusted_work_area_.set_x(adjusted_work_area_.x() + space); |
| 550 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); | 153 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); |
| 551 } | 154 } |
| 552 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_RIGHT)) { | 155 if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_RIGHT)) { |
| 553 int space = auto_hiding_desktop_bar_->GetThickness( | 156 int space = auto_hiding_desktop_bar_->GetThickness( |
| 554 AutoHidingDesktopBar::ALIGN_RIGHT); | 157 AutoHidingDesktopBar::ALIGN_RIGHT); |
| 555 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); | 158 adjusted_work_area_.set_width(adjusted_work_area_.width() - space); |
| 556 } | 159 } |
| 557 } | 160 } |
| 558 | 161 |
| 559 int PanelManager::GetBottomPositionForExpansionState( | 162 int PanelManager::GetBottomPositionForExpansionState( |
| 560 Panel::ExpansionState expansion_state) const { | 163 Panel::ExpansionState expansion_state) const { |
| 561 int bottom = adjusted_work_area_.bottom(); | 164 return panel_strip_->GetBottomPositionForExpansionState(expansion_state); |
| 562 // If there is an auto-hiding desktop bar aligned to the bottom edge, we need | |
| 563 // to move the title-only panel above the auto-hiding desktop bar. | |
| 564 if (expansion_state == Panel::TITLE_ONLY && | |
| 565 auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM)) { | |
| 566 bottom -= auto_hiding_desktop_bar_->GetThickness( | |
| 567 AutoHidingDesktopBar::ALIGN_BOTTOM); | |
| 568 } | |
| 569 | |
| 570 return bottom; | |
| 571 } | 165 } |
| 572 | 166 |
| 573 BrowserWindow* PanelManager::GetNextBrowserWindowToActivate( | 167 BrowserWindow* PanelManager::GetNextBrowserWindowToActivate( |
| 574 Panel* panel) const { | 168 Panel* panel) const { |
| 575 // Find the last active browser window that is not minimized. | 169 // Find the last active browser window that is not minimized. |
| 576 BrowserList::const_reverse_iterator iter = BrowserList::begin_last_active(); | 170 BrowserList::const_reverse_iterator iter = BrowserList::begin_last_active(); |
| 577 BrowserList::const_reverse_iterator end = BrowserList::end_last_active(); | 171 BrowserList::const_reverse_iterator end = BrowserList::end_last_active(); |
| 578 for (; (iter != end); ++iter) { | 172 for (; (iter != end); ++iter) { |
| 579 Browser* browser = *iter; | 173 Browser* browser = *iter; |
| 580 if (panel->browser() != browser && !browser->window()->IsMinimized()) | 174 if (panel->browser() != browser && !browser->window()->IsMinimized()) |
| 581 return browser->window(); | 175 return browser->window(); |
| 582 } | 176 } |
| 583 | 177 |
| 584 return NULL; | 178 return NULL; |
| 585 } | 179 } |
| 586 | 180 |
| 587 void PanelManager::MoveToPanelStrip(Panel* panel) { | |
| 588 // TODO(jennb) - implement. | |
| 589 } | |
| 590 | |
| 591 void PanelManager::MoveToOverflowStrip(Panel* panel, bool is_new) { | 181 void PanelManager::MoveToOverflowStrip(Panel* panel, bool is_new) { |
| 592 // TODO(jianli) - implement. | 182 // TODO(jianli) - implement. |
| 593 } | 183 } |
| 594 | 184 |
| 595 void PanelManager::OnMouseMove(const gfx::Point& mouse_position) { | |
| 596 bool bring_up_titlebars = ShouldBringUpTitlebars(mouse_position.x(), | |
| 597 mouse_position.y()); | |
| 598 BringUpOrDownTitlebars(bring_up_titlebars); | |
| 599 } | |
| 600 | |
| 601 void PanelManager::OnAutoHidingDesktopBarThicknessChanged() { | 185 void PanelManager::OnAutoHidingDesktopBarThicknessChanged() { |
| 602 AdjustWorkAreaForAutoHidingDesktopBars(); | 186 AdjustWorkAreaForAutoHidingDesktopBars(); |
| 603 Rearrange(panels_.begin(), StartingRightPosition()); | 187 Layout(); |
| 604 } | 188 } |
| 605 | 189 |
| 606 void PanelManager::OnAutoHidingDesktopBarVisibilityChanged( | 190 void PanelManager::OnAutoHidingDesktopBarVisibilityChanged( |
| 607 AutoHidingDesktopBar::Alignment alignment, | 191 AutoHidingDesktopBar::Alignment alignment, |
| 608 AutoHidingDesktopBar::Visibility visibility) { | 192 AutoHidingDesktopBar::Visibility visibility) { |
| 609 if (delayed_titlebar_action_ == NO_ACTION) | 193 panel_strip_->OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility); |
| 610 return; | |
| 611 | |
| 612 AutoHidingDesktopBar::Visibility expected_visibility = | |
| 613 delayed_titlebar_action_ == BRING_UP ? AutoHidingDesktopBar::VISIBLE | |
| 614 : AutoHidingDesktopBar::HIDDEN; | |
| 615 if (visibility != expected_visibility) | |
| 616 return; | |
| 617 | |
| 618 DoBringUpOrDownTitlebars(delayed_titlebar_action_ == BRING_UP); | |
| 619 delayed_titlebar_action_ = NO_ACTION; | |
| 620 } | |
| 621 | |
| 622 void PanelManager::Rearrange(Panels::iterator iter_to_start, | |
| 623 int rightmost_position) { | |
| 624 for (Panels::iterator iter = iter_to_start; iter != panels_.end(); ++iter) { | |
| 625 Panel* panel = *iter; | |
| 626 gfx::Rect new_bounds(panel->GetBounds()); | |
| 627 new_bounds.set_x(rightmost_position - new_bounds.width()); | |
| 628 new_bounds.set_y( | |
| 629 GetBottomPositionForExpansionState(panel->expansion_state()) - | |
| 630 new_bounds.height()); | |
| 631 if (new_bounds != panel->GetBounds()) | |
| 632 panel->SetPanelBounds(new_bounds); | |
| 633 | |
| 634 rightmost_position = new_bounds.x() - kPanelsHorizontalSpacing; | |
| 635 } | |
| 636 } | 194 } |
| 637 | 195 |
| 638 void PanelManager::RemoveAll() { | 196 void PanelManager::RemoveAll() { |
| 639 // This should not be called when we're in the process of dragging. | 197 panel_strip_->RemoveAll(); |
| 640 DCHECK(dragging_panel_index_ == kInvalidPanelIndex); | 198 // TODO(jianli): overflow_strip_->RemoveAll(); |
| 199 } |
| 641 | 200 |
| 642 // Make a copy of the iterator as closing panels can modify the vector. | 201 int PanelManager::num_panels() const { |
| 643 Panels panels_copy = panels_; | 202 return panel_strip_->num_panels(); |
| 644 | 203 // TODO(jianli): + overflow_strip_->num_panels(); |
| 645 // Start from the bottom to avoid reshuffling. | |
| 646 for (Panels::reverse_iterator iter = panels_copy.rbegin(); | |
| 647 iter != panels_copy.rend(); ++iter) | |
| 648 (*iter)->Close(); | |
| 649 } | 204 } |
| 650 | 205 |
| 651 bool PanelManager::is_dragging_panel() const { | 206 bool PanelManager::is_dragging_panel() const { |
| 652 return dragging_panel_index_ != kInvalidPanelIndex; | 207 return panel_strip_->is_dragging_panel(); |
| 653 } | 208 } |
| 209 |
| 210 const PanelManager::Panels& PanelManager::panels() const { |
| 211 return panel_strip_->panels(); |
| 212 } |
| OLD | NEW |