diff options
author | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-03 00:54:56 +0000 |
---|---|---|
committer | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-03 00:54:56 +0000 |
commit | 5b7cb5670cb2a1f9154c39e0dea8a104b2293aa8 (patch) | |
tree | ecf3da721e02e1fbcbc438ae8782f27f242de139 /chrome/browser/ui/panels | |
parent | 8fe148521b21b213f9d32612bcebe515c47863f7 (diff) | |
download | chromium_src-5b7cb5670cb2a1f9154c39e0dea8a104b2293aa8.zip chromium_src-5b7cb5670cb2a1f9154c39e0dea8a104b2293aa8.tar.gz chromium_src-5b7cb5670cb2a1f9154c39e0dea8a104b2293aa8.tar.bz2 |
Add PanelOverflowStrip to handle panel overflow.
BUG=none
TEST=overflow test
Review URL: http://codereview.chromium.org/8776035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112833 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui/panels')
-rw-r--r-- | chrome/browser/ui/panels/panel.cc | 55 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel.h | 12 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_browser_frame_view.cc | 2 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_browser_frame_view.h | 2 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_browser_view.cc | 56 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_browser_view.h | 2 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_browser_view_browsertest.cc | 2 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_browsertest.cc | 41 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_manager.cc | 31 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_manager.h | 20 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_overflow_strip.cc | 220 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_overflow_strip.h | 101 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_strip.cc | 68 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_strip.h | 15 |
14 files changed, 520 insertions, 107 deletions
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc index 401b71b..4667065 100644 --- a/chrome/browser/ui/panels/panel.cc +++ b/chrome/browser/ui/panels/panel.cc @@ -12,6 +12,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/panels/native_panel.h" #include "chrome/browser/ui/panels/panel_manager.h" +#include "chrome/browser/ui/panels/panel_overflow_strip.h" +#include "chrome/browser/ui/panels/panel_strip.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/ui/window_sizer.h" #include "chrome/browser/web_applications/web_app.h" @@ -121,34 +123,10 @@ void Panel::SetSizeRange(const gfx::Size& min_size, const gfx::Size& max_size) { void Panel::SetExpansionState(ExpansionState new_state) { if (expansion_state_ == new_state) return; - ExpansionState old_state = expansion_state_; expansion_state_ = new_state; - int height; - switch (expansion_state_) { - case EXPANDED: - height = restored_size_.height(); - break; - case TITLE_ONLY: - height = native_panel_->TitleOnlyHeight(); - break; - case MINIMIZED: - height = kMinimizedPanelHeight; - break; - default: - NOTREACHED(); - height = restored_size_.height(); - break; - } - - int bottom = manager()->GetBottomPositionForExpansionState(expansion_state_); - gfx::Rect bounds = native_panel_->GetPanelBounds(); - bounds.set_y(bottom - height); - bounds.set_height(height); - SetPanelBounds(bounds); - - manager()->OnPanelExpansionStateChanged(old_state, new_state); + manager()->OnPanelExpansionStateChanged(this, old_state); // The minimized panel should not get the focus. if (expansion_state_ == MINIMIZED) @@ -189,7 +167,11 @@ void Panel::FullScreenModeChanged(bool is_full_screen) { } void Panel::Show() { - native_panel_->ShowPanel(); + // Don't show panel as active if it is in overflow state. + if (expansion_state_ == IN_OVERFLOW) + ShowInactive(); + else + native_panel_->ShowPanel(); } void Panel::ShowInactive() { @@ -207,7 +189,16 @@ void Panel::Close() { native_panel_->ClosePanel(); } +void Panel::MoveOutOfOverflow() { + if (expansion_state_ != Panel::IN_OVERFLOW) + return; + manager()->panel_overflow_strip()->Remove(this); + manager()->panel_strip()->AddPanel(this); +} + void Panel::Activate() { + MoveOutOfOverflow(); + // Make sure the panel is expanded when activated programmatically, // so the user input does not go into collapsed window. SetExpansionState(Panel::EXPANDED); @@ -278,6 +269,18 @@ gfx::Rect Panel::GetBounds() const { return native_panel_->GetPanelBounds(); } +int Panel::TitleOnlyHeight() const { + return native_panel_->TitleOnlyHeight(); +} + +gfx::Size Panel::IconOnlySize() const { + return native_panel_->IconOnlySize(); +} + +void Panel::EnsureFullyVisible() { + native_panel_->EnsurePanelFullyVisible(); +} + bool Panel::IsMaximized() const { // Size of panels is managed by PanelManager, they are never 'zoomed'. return false; diff --git a/chrome/browser/ui/panels/panel.h b/chrome/browser/ui/panels/panel.h index 094e523..c9f4eab 100644 --- a/chrome/browser/ui/panels/panel.h +++ b/chrome/browser/ui/panels/panel.h @@ -69,6 +69,18 @@ class Panel : public BrowserWindow, // b) it remains on top when an app exits full screen mode. void FullScreenModeChanged(bool is_full_screen); + void MoveOutOfOverflow(); + + // Ensures that the panel is fully visible, that is, not obscured by other + // top-most windows. + void EnsureFullyVisible(); + + int TitleOnlyHeight() const; + + // Returns the size of the panel when it is iconified, as shown on the + // overflow area. + gfx::Size IconOnlySize() const; + // BrowserWindow overrides. virtual void Show() OVERRIDE; virtual void ShowInactive() OVERRIDE; diff --git a/chrome/browser/ui/panels/panel_browser_frame_view.cc b/chrome/browser/ui/panels/panel_browser_frame_view.cc index e83cb46..442eea8 100644 --- a/chrome/browser/ui/panels/panel_browser_frame_view.cc +++ b/chrome/browser/ui/panels/panel_browser_frame_view.cc @@ -660,7 +660,7 @@ int PanelBrowserFrameView::IconOnlyWidth() const { return kBorderThickness * 2 + kIconAndBorderSpacing * 2 + kIconSize; } -gfx::Size PanelBrowserFrameView::IconifiedSize() const { +gfx::Size PanelBrowserFrameView::IconOnlySize() const { return gfx::Size(IconOnlyWidth(), NonClientTopBorderHeight()); } diff --git a/chrome/browser/ui/panels/panel_browser_frame_view.h b/chrome/browser/ui/panels/panel_browser_frame_view.h index ab6ba76..f9e103b 100644 --- a/chrome/browser/ui/panels/panel_browser_frame_view.h +++ b/chrome/browser/ui/panels/panel_browser_frame_view.h @@ -56,7 +56,7 @@ class PanelBrowserFrameView : public BrowserNonClientFrameView, // Returns the size of the non-client area upon which only the title icon // is drawn. - gfx::Size IconifiedSize() const; + gfx::Size IconOnlySize() const; protected: // Overridden from BrowserNonClientFrameView: diff --git a/chrome/browser/ui/panels/panel_browser_view.cc b/chrome/browser/ui/panels/panel_browser_view.cc index 3b217ef..6bb2108 100644 --- a/chrome/browser/ui/panels/panel_browser_view.cc +++ b/chrome/browser/ui/panels/panel_browser_view.cc @@ -9,6 +9,8 @@ #include "chrome/browser/ui/panels/panel.h" #include "chrome/browser/ui/panels/panel_browser_frame_view.h" #include "chrome/browser/ui/panels/panel_manager.h" +#include "chrome/browser/ui/panels/panel_overflow_strip.h" +#include "chrome/browser/ui/panels/panel_strip.h" #include "chrome/browser/ui/views/frame/browser_frame.h" #include "chrome/browser/ui/webui/task_manager_dialog.h" #include "chrome/common/chrome_notification_types.h" @@ -114,15 +116,25 @@ void PanelBrowserView::SetBounds(const gfx::Rect& bounds) { SetBoundsInternal(bounds, true); } -void PanelBrowserView::SetBoundsInternal(const gfx::Rect& bounds, +void PanelBrowserView::SetBoundsInternal(const gfx::Rect& new_bounds, bool animate) { - if (bounds_ == bounds) + if (bounds_ == new_bounds) return; - bounds_ = bounds; + + // TODO(jianli): this is just a temporary hack to check if we need to show + // or hide the panel app icon in the taskbar. http://crbug.com/106227 + int panel_strip_area_left = + panel()->manager()->panel_strip()->display_area().x(); + bool app_icon_shown = bounds_.x() >= panel_strip_area_left; + bool app_icon_to_show = new_bounds.x() >= panel_strip_area_left; + if (app_icon_shown != app_icon_to_show) + ShowOrHidePanelAppIcon(app_icon_to_show); + + bounds_ = new_bounds; // No animation if the panel is being dragged. if (!animate || mouse_dragging_state_ == DRAGGING_STARTED) { - ::BrowserView::SetBounds(bounds); + ::BrowserView::SetBounds(new_bounds); return; } @@ -398,12 +410,16 @@ void PanelBrowserView::DestroyPanelBrowser() { } gfx::Size PanelBrowserView::IconOnlySize() const { - // TODO(jianli): to be implemented. - return gfx::Size(); + return GetFrameView()->IconOnlySize(); } void PanelBrowserView::EnsurePanelFullyVisible() { - // TODO(jianli): to be implemented. +#if defined(OS_WIN) && !defined(USE_AURA) + ::SetWindowPos(GetNativeHandle(), HWND_TOP, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +#else + NOTIMPLEMENTED(); +#endif } PanelBrowserFrameView* PanelBrowserView::GetFrameView() const { @@ -426,6 +442,10 @@ bool PanelBrowserView::OnTitlebarMouseDragged(const gfx::Point& location) { if (!mouse_pressed_) return false; + // Dragging is not supported for overflow panel. + if (panel_->expansion_state() == Panel::IN_OVERFLOW) + return true; + gfx::Point last_mouse_location = mouse_location_; // |location| is in the view's coordinate system. Convert it to the screen @@ -466,6 +486,12 @@ bool PanelBrowserView::OnTitlebarMouseReleased() { if (mouse_dragging_state_ != NO_DRAGGING) return true; + // If the panel is in overflow, move it to the normal strip. + if (panel_->expansion_state() == Panel::IN_OVERFLOW) { + panel_->MoveOutOfOverflow(); + return true; + } + // Do not minimize the panel when we just clear the attention state. This is // a hack to prevent the panel from being minimized when the user clicks on // the title-bar to clear the attention. @@ -504,6 +530,22 @@ bool PanelBrowserView::EndDragging(bool cancelled) { return true; } +void PanelBrowserView::ShowOrHidePanelAppIcon(bool show) { +#if defined(OS_WIN) && !defined(USE_AURA) + gfx::NativeWindow native_window = GetNativeHandle(); + ::ShowWindow(native_window, SW_HIDE); + int style = ::GetWindowLong(native_window, GWL_EXSTYLE); + if (show) + style &= (~WS_EX_TOOLWINDOW); + else + style |= WS_EX_TOOLWINDOW; + ::SetWindowLong(native_window, GWL_EXSTYLE, style); + ::ShowWindow(native_window, SW_SHOWNA); +#else + NOTIMPLEMENTED(); +#endif +} + // NativePanelTesting implementation. class NativePanelTestingWin : public NativePanelTesting { public: diff --git a/chrome/browser/ui/panels/panel_browser_view.h b/chrome/browser/ui/panels/panel_browser_view.h index 9873ed2..99506df 100644 --- a/chrome/browser/ui/panels/panel_browser_view.h +++ b/chrome/browser/ui/panels/panel_browser_view.h @@ -122,6 +122,8 @@ class PanelBrowserView : public BrowserView, void SetBoundsInternal(const gfx::Rect& bounds, bool animate); + void ShowOrHidePanelAppIcon(bool show); + scoped_ptr<Panel> panel_; gfx::Rect bounds_; diff --git a/chrome/browser/ui/panels/panel_browser_view_browsertest.cc b/chrome/browser/ui/panels/panel_browser_view_browsertest.cc index 100c548..2db40e9 100644 --- a/chrome/browser/ui/panels/panel_browser_view_browsertest.cc +++ b/chrome/browser/ui/panels/panel_browser_view_browsertest.cc @@ -616,7 +616,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, DISABLED_DrawAttention) { } IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, - DISABLED_ChangeAutoHideTaskBarThickness) { + ChangeAutoHideTaskBarThickness) { TestChangeAutoHideTaskBarThickness(); } #endif diff --git a/chrome/browser/ui/panels/panel_browsertest.cc b/chrome/browser/ui/panels/panel_browsertest.cc index f7e12e4..63c15df 100644 --- a/chrome/browser/ui/panels/panel_browsertest.cc +++ b/chrome/browser/ui/panels/panel_browsertest.cc @@ -27,7 +27,9 @@ #include "chrome/browser/ui/panels/native_panel.h" #include "chrome/browser/ui/panels/panel.h" #include "chrome/browser/ui/panels/panel_manager.h" +#include "chrome/browser/ui/panels/panel_overflow_strip.h" #include "chrome/browser/ui/panels/panel_settings_menu_model.h" +#include "chrome/browser/ui/panels/panel_strip.h" #include "chrome/browser/ui/panels/test_panel_mouse_watcher.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_notification_types.h" @@ -81,6 +83,9 @@ class PanelBrowserTest : public BasePanelBrowserTest { void TestCreatePanelOnOverflow() { PanelManager* panel_manager = PanelManager::GetInstance(); + PanelStrip* panel_strip = panel_manager->panel_strip(); + PanelOverflowStrip* panel_overflow_strip = + panel_manager->panel_overflow_strip(); EXPECT_EQ(0, panel_manager->num_panels()); // No panels initially. // Create testing extensions. @@ -106,42 +111,50 @@ class PanelBrowserTest : public BasePanelBrowserTest { web_app::GenerateApplicationNameFromExtensionId(extension1->id()), gfx::Rect(0, 0, 200, 200)); ASSERT_EQ(3, panel_manager->num_panels()); + EXPECT_EQ(3, panel_strip->num_panels()); + EXPECT_EQ(0, panel_overflow_strip->num_panels()); // Open a panel that would overflow. Panel* panel4 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension2->id()), gfx::Rect(0, 0, 280, 200)); ASSERT_EQ(4, panel_manager->num_panels()); - EXPECT_LT(panel4->GetBounds().right(), panel3->GetBounds().x()); - EXPECT_GT(0, panel4->GetBounds().x()); + EXPECT_EQ(3, panel_strip->num_panels()); + EXPECT_EQ(1, panel_overflow_strip->num_panels()); + EXPECT_EQ(Panel::IN_OVERFLOW, panel4->expansion_state()); // Open another panel that would overflow. Panel* panel5 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension3->id()), gfx::Rect(0, 0, 300, 200)); ASSERT_EQ(5, panel_manager->num_panels()); - EXPECT_LT(panel5->GetBounds().right(), panel4->GetBounds().x()); - EXPECT_GT(0, panel5->GetBounds().x()); + EXPECT_EQ(3, panel_strip->num_panels()); + EXPECT_EQ(2, panel_overflow_strip->num_panels()); + EXPECT_EQ(Panel::IN_OVERFLOW, panel4->expansion_state()); + EXPECT_EQ(Panel::IN_OVERFLOW, panel5->expansion_state()); - // Close a visible panel. Expect an overflow panel to slide over. + // Close a visible panel. Expect an overflow panel to move over. CloseWindowAndWait(panel2->browser()); ASSERT_EQ(4, panel_manager->num_panels()); - EXPECT_LT(panel4->GetBounds().right(), panel3->GetBounds().x()); - EXPECT_LE(0, panel4->GetBounds().x()); - EXPECT_GT(0, panel5->GetBounds().x()); + EXPECT_EQ(3, panel_strip->num_panels()); + EXPECT_EQ(1, panel_overflow_strip->num_panels()); + EXPECT_NE(Panel::IN_OVERFLOW, panel4->expansion_state()); + EXPECT_EQ(Panel::IN_OVERFLOW, panel5->expansion_state()); - // Close another visible panel. Remaining overflow panel should slide over - // but still not enough room to be fully visible. + // Close another visible panel. Remaining overflow panel cannot move over + // due to not enough room. CloseWindowAndWait(panel3->browser()); ASSERT_EQ(3, panel_manager->num_panels()); - EXPECT_LT(panel5->GetBounds().right(), panel4->GetBounds().x()); - EXPECT_GT(0, panel5->GetBounds().x()); + EXPECT_EQ(2, panel_strip->num_panels()); + EXPECT_EQ(1, panel_overflow_strip->num_panels()); + EXPECT_EQ(Panel::IN_OVERFLOW, panel5->expansion_state()); // Closing one more panel makes room for all panels to fit on screen. CloseWindowAndWait(panel4->browser()); ASSERT_EQ(2, panel_manager->num_panels()); - EXPECT_LT(panel5->GetBounds().right(), panel1->GetBounds().x()); - EXPECT_LE(0, panel5->GetBounds().x()); + EXPECT_EQ(2, panel_strip->num_panels()); + EXPECT_EQ(0, panel_overflow_strip->num_panels()); + EXPECT_NE(Panel::IN_OVERFLOW, panel5->expansion_state()); panel1->Close(); panel5->Close(); diff --git a/chrome/browser/ui/panels/panel_manager.cc b/chrome/browser/ui/panels/panel_manager.cc index 122381d..30eb6cd 100644 --- a/chrome/browser/ui/panels/panel_manager.cc +++ b/chrome/browser/ui/panels/panel_manager.cc @@ -10,6 +10,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/panels/panel_mouse_watcher.h" +#include "chrome/browser/ui/panels/panel_overflow_strip.h" #include "chrome/browser/ui/panels/panel_strip.h" #include "chrome/browser/ui/window_sizer.h" #include "chrome/common/chrome_notification_types.h" @@ -41,6 +42,7 @@ PanelManager::PanelManager() auto_sizing_enabled_(true), is_full_screen_(false) { panel_strip_.reset(new PanelStrip(this)); + panel_overflow_strip_.reset(new PanelOverflowStrip(this)); auto_hiding_desktop_bar_ = AutoHidingDesktopBar::Create(this); OnDisplayChanged(); } @@ -81,6 +83,10 @@ void PanelManager::Layout() { kPanelStripLeftMargin - kPanelStripRightMargin); panel_strip_bounds.set_height(height); panel_strip_->SetDisplayArea(panel_strip_bounds); + + gfx::Rect overflow_area(adjusted_work_area_); + overflow_area.set_width(kOverflowStripThickness); + panel_overflow_strip_->SetDisplayArea(overflow_area); } Panel* PanelManager::CreatePanel(Browser* browser) { @@ -113,6 +119,7 @@ void PanelManager::CheckFullScreenMode() { return; is_full_screen_ = is_full_screen_new; panel_strip_->OnFullScreenModeChanged(is_full_screen_); + panel_overflow_strip_->OnFullScreenModeChanged(is_full_screen_); } void PanelManager::Remove(Panel* panel) { @@ -121,7 +128,8 @@ void PanelManager::Remove(Panel* panel) { if (panel_strip_->Remove(panel)) return; - // TODO(jianli): else try removing from overflow strip + bool removed = panel_overflow_strip_->Remove(panel); + DCHECK(removed); } void PanelManager::OnPanelRemoved(Panel* panel) { @@ -144,8 +152,11 @@ void PanelManager::EndDragging(bool cancelled) { } void PanelManager::OnPanelExpansionStateChanged( - Panel::ExpansionState old_state, Panel::ExpansionState new_state) { - panel_strip_->OnPanelExpansionStateChanged(old_state, new_state); + Panel* panel, Panel::ExpansionState old_state) { + if (panel->expansion_state() == Panel::IN_OVERFLOW) + panel_overflow_strip_->OnPanelExpansionStateChanged(panel, old_state); + else + panel_strip_->OnPanelExpansionStateChanged(panel, old_state); } void PanelManager::OnPreferredWindowSizeChanged( @@ -180,11 +191,6 @@ void PanelManager::AdjustWorkAreaForAutoHidingDesktopBars() { } } -int PanelManager::GetBottomPositionForExpansionState( - Panel::ExpansionState expansion_state) const { - return panel_strip_->GetBottomPositionForExpansionState(expansion_state); -} - BrowserWindow* PanelManager::GetNextBrowserWindowToActivate( Panel* panel) const { // Find the last active browser window that is not minimized. @@ -199,10 +205,6 @@ BrowserWindow* PanelManager::GetNextBrowserWindowToActivate( return NULL; } -void PanelManager::MoveToOverflowStrip(Panel* panel, bool is_new) { - // TODO(jianli) - implement. -} - void PanelManager::OnAutoHidingDesktopBarThicknessChanged() { AdjustWorkAreaForAutoHidingDesktopBars(); Layout(); @@ -216,12 +218,11 @@ void PanelManager::OnAutoHidingDesktopBarVisibilityChanged( void PanelManager::RemoveAll() { panel_strip_->RemoveAll(); - // TODO(jianli): overflow_strip_->RemoveAll(); + panel_overflow_strip_->RemoveAll(); } int PanelManager::num_panels() const { - return panel_strip_->num_panels(); - // TODO(jianli): + overflow_strip_->num_panels(); + return panel_strip_->num_panels() + panel_overflow_strip_->num_panels(); } bool PanelManager::is_dragging_panel() const { diff --git a/chrome/browser/ui/panels/panel_manager.h b/chrome/browser/ui/panels/panel_manager.h index 897a84e..b78cb9e 100644 --- a/chrome/browser/ui/panels/panel_manager.h +++ b/chrome/browser/ui/panels/panel_manager.h @@ -24,6 +24,7 @@ class Browser; class PanelMouseWatcher; +class PanelOverflowStrip; class PanelStrip; // This class manages a set of panels. @@ -53,8 +54,8 @@ class PanelManager : public AutoHidingDesktopBar::Observer { void EndDragging(bool cancelled); // Invoked when a panel's expansion state changes. - void OnPanelExpansionStateChanged(Panel::ExpansionState old_state, - Panel::ExpansionState new_state); + void OnPanelExpansionStateChanged(Panel* panel, + Panel::ExpansionState old_state); // Invoked when the preferred window size of the given panel might need to // get changed. @@ -68,12 +69,6 @@ class PanelManager : public AutoHidingDesktopBar::Observer { // Brings up or down the titlebars for all minimized panels. void BringUpOrDownTitlebars(bool bring_up); - // Returns the bottom position for the panel per its expansion state. If auto- - // hide bottom bar is present, we want to move the minimized panel to the - // bottom of the screen, not the bottom of the work area. - int GetBottomPositionForExpansionState( - Panel::ExpansionState expansion_state) const; - // Returns the next browser window which could be either panel window or // tabbed window, to switch to if the given panel is going to be deactivated. // Returns NULL if such window cannot be found. @@ -84,11 +79,6 @@ class PanelManager : public AutoHidingDesktopBar::Observer { int StartingRightPosition() const; const Panels& panels() const; - // Moves a panel to the overflow strip. The panel does not currently - // belong in any other strip. - // |is_new| is true if the panel was just created. - void MoveToOverflowStrip(Panel* panel, bool is_new); - AutoHidingDesktopBar* auto_hiding_desktop_bar() const { return auto_hiding_desktop_bar_; } @@ -102,6 +92,9 @@ class PanelManager : public AutoHidingDesktopBar::Observer { } bool is_full_screen() const { return is_full_screen_; } + PanelOverflowStrip* panel_overflow_strip() const { + return panel_overflow_strip_.get(); + } #ifdef UNIT_TEST static int horizontal_spacing() { return PanelStrip::horizontal_spacing(); } @@ -162,6 +155,7 @@ class PanelManager : public AutoHidingDesktopBar::Observer { void CheckFullScreenMode(); scoped_ptr<PanelStrip> panel_strip_; + scoped_ptr<PanelOverflowStrip> panel_overflow_strip_; // Use a mouse watcher to know when to bring up titlebars to "peek" at // minimized panels. Mouse movement is only tracked when there is a minimized diff --git a/chrome/browser/ui/panels/panel_overflow_strip.cc b/chrome/browser/ui/panels/panel_overflow_strip.cc new file mode 100644 index 0000000..ed7c8ed --- /dev/null +++ b/chrome/browser/ui/panels/panel_overflow_strip.cc @@ -0,0 +1,220 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/panels/panel_overflow_strip.h" + +#include "base/logging.h" +#include "chrome/browser/ui/panels/panel_manager.h" +#include "chrome/browser/ui/panels/panel_mouse_watcher.h" +#include "chrome/browser/ui/panels/panel_strip.h" +#include "ui/base/animation/slide_animation.h" + +namespace { +// The width of the overflow area that is expanded to show more info, i.e. +// titles, when the mouse hovers over the area. +const int kOverflowAreaHoverWidth = 200; + +// Maximium number of overflow panels allowed to be shown. +const size_t kMaxVisibleOverflowPanelsAllowed = 6; + +// This value is experimental and subjective. +const int kOverflowHoverAnimationMs = 180; +} + +PanelOverflowStrip::PanelOverflowStrip(PanelManager* panel_manager) + : panel_manager_(panel_manager), + are_overflow_titles_shown_(false), + overflow_hover_animator_start_width_(0), + overflow_hover_animator_end_width_(0) { +} + +PanelOverflowStrip::~PanelOverflowStrip() { + DCHECK(panels_.empty()); +} + +void PanelOverflowStrip::SetDisplayArea(const gfx::Rect& display_area) { + if (display_area_ == display_area) + return; + + display_area_ = display_area; + Refresh(); +} + +void PanelOverflowStrip::AddPanel(Panel* panel, bool is_new) { + // TODO(jianli): consider using other container to improve the perf for + // inserting to the front. http://crbug.com/106222 + if (is_new) + panels_.push_back(panel); + else + panels_.insert(panels_.begin(), panel); + + if (panels_.size() == 1) + panel_manager_->mouse_watcher()->AddObserver(this); + + panel->SetExpansionState(Panel::IN_OVERFLOW); + + if (is_new) { + // When the overflow panel is added to the back, only need to refresh + // itself. + DoRefresh(panels_.size() - 1, panels_.size() - 1); + } else { + // When the overflow panel is added to the front, refresh all. + Refresh(); + } +} + +bool PanelOverflowStrip::Remove(Panel* panel) { + size_t index = 0; + for (Panels::iterator iter = panels_.begin(); iter != panels_.end(); + ++iter, ++index) { + if (*iter == panel) { + panels_.erase(iter); + DoRefresh(index, panels_.size() - 1); + panel_manager_->OnPanelRemoved(panel); + if (panels_.empty()) + panel_manager_->mouse_watcher()->RemoveObserver(this); + return true; + } + } + return false; +} + +void PanelOverflowStrip::RemoveAll() { + // Make a copy of the iterator as closing panels can modify the vector. + Panels panels_copy = panels_; + + // Start from the bottom to avoid reshuffling. + for (Panels::reverse_iterator iter = panels_copy.rbegin(); + iter != panels_copy.rend(); ++iter) + (*iter)->Close(); +} + +void PanelOverflowStrip::OnPanelExpansionStateChanged( + Panel* panel, Panel::ExpansionState old_state) { + DCHECK(panel->expansion_state() == Panel::IN_OVERFLOW); +} + +void PanelOverflowStrip::Refresh() { + if (panels_.empty()) + return; + DoRefresh(0, panels_.size() - 1); +} + +void PanelOverflowStrip::DoRefresh(size_t start_index, size_t end_index) { + if (panels_.empty()) + return; + + DCHECK(start_index < panels_.size()); + DCHECK(end_index < panels_.size()); + + for (size_t index = start_index; index <= end_index; ++index) { + Panel* panel = panels_[index]; + gfx::Rect new_bounds = ComputeLayout(index, + panel->IconOnlySize()); + DCHECK(!new_bounds.IsEmpty()); + panel->SetPanelBounds(new_bounds); + } +} + +gfx::Rect PanelOverflowStrip::ComputeLayout( + size_t index, const gfx::Size& iconified_size) const { + DCHECK(index != kInvalidPanelIndex); + + gfx::Rect bounds; + int bottom = (index == 0) ? display_area_.bottom() : + panels_[index - 1]->GetBounds().y(); + bounds.set_x(display_area_.x()); + bounds.set_y(bottom - iconified_size.height()); + + if (are_overflow_titles_shown_) { + // Both icon and title are visible when the mouse hovers over the overflow + // area. + bounds.set_width(kOverflowAreaHoverWidth); + bounds.set_height(iconified_size.height()); + } else if (index < kMaxVisibleOverflowPanelsAllowed) { + // Only the icon is visible. + bounds.set_width(iconified_size.width()); + bounds.set_height(iconified_size.height()); + } else { + // Invisible for overflow-on-overflow. + bounds.set_width(0); + bounds.set_height(0); + } + + return bounds; +} + +void PanelOverflowStrip::OnMouseMove(const gfx::Point& mouse_position) { + bool show_overflow_titles = ShouldShowOverflowTitles(mouse_position); + ShowOverflowTitles(show_overflow_titles); +} + +bool PanelOverflowStrip::ShouldShowOverflowTitles( + const gfx::Point& mouse_position) const { + if (panels_.empty()) + return false; + + int width = are_overflow_titles_shown_ ? kOverflowAreaHoverWidth + : display_area_.width(); + return display_area_.x() <= mouse_position.x() && + mouse_position.x() <= display_area_.x() + width && + panels_.back()->GetBounds().y() <= mouse_position.y() && + mouse_position.y() <= display_area_.bottom(); +} + +void PanelOverflowStrip::ShowOverflowTitles(bool show_overflow_titles) { + if (show_overflow_titles == are_overflow_titles_shown_) + return; + are_overflow_titles_shown_ = show_overflow_titles; + + if (show_overflow_titles) { + overflow_hover_animator_start_width_ = display_area_.width(); + overflow_hover_animator_end_width_ = kOverflowAreaHoverWidth; + + // We need to bring all overflow panels to the top of z-order since the + // active panel might obscure the expanded overflow panels. + for (Panels::iterator iter = panels_.begin(); + iter != panels_.end(); ++iter) { + (*iter)->EnsureFullyVisible(); + } + } else { + overflow_hover_animator_start_width_ = kOverflowAreaHoverWidth; + overflow_hover_animator_end_width_ = display_area_.width(); + } + + if (!overflow_hover_animator_.get()) + overflow_hover_animator_.reset(new ui::SlideAnimation(this)); + if (overflow_hover_animator_->IsShowing()) + overflow_hover_animator_->Reset(); + overflow_hover_animator_->SetSlideDuration(kOverflowHoverAnimationMs); + + overflow_hover_animator_->Show(); +} + +void PanelOverflowStrip::AnimationProgressed(const ui::Animation* animation) { + int current_width = overflow_hover_animator_->CurrentValueBetween( + overflow_hover_animator_start_width_, overflow_hover_animator_end_width_); + bool end_of_shrinking = current_width == display_area_.width(); + + // Update each overflow panel. + for (size_t i = 0; i < panels_.size(); ++i) { + Panel* overflow_panel = panels_[i]; + gfx::Rect bounds = overflow_panel->GetBounds(); + + if (i >= kMaxVisibleOverflowPanelsAllowed && end_of_shrinking) { + bounds.set_width(0); + bounds.set_height(0); + } else { + bounds.set_width(current_width); + bounds.set_height(overflow_panel->IconOnlySize().height()); + } + + overflow_panel->SetPanelBoundsInstantly(bounds); + } +} + +void PanelOverflowStrip::OnFullScreenModeChanged(bool is_full_screen) { + for (size_t i = 0; i < panels_.size(); ++i) + panels_[i]->FullScreenModeChanged(is_full_screen); +} diff --git a/chrome/browser/ui/panels/panel_overflow_strip.h b/chrome/browser/ui/panels/panel_overflow_strip.h new file mode 100644 index 0000000..0dab64d --- /dev/null +++ b/chrome/browser/ui/panels/panel_overflow_strip.h @@ -0,0 +1,101 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_PANELS_PANEL_OVERFLOW_STRIP_H_ +#define CHROME_BROWSER_UI_PANELS_PANEL_OVERFLOW_STRIP_H_ +#pragma once + +#include <vector> +#include "chrome/browser/ui/panels/panel.h" +#include "chrome/browser/ui/panels/panel_mouse_watcher_observer.h" +#include "ui/base/animation/animation_delegate.h" + +class Browser; +class PanelManager; +namespace ui { +class SlideAnimation; +} + +// Manipulates all the panels that are placed on the left-most overflow area. +class PanelOverflowStrip : public PanelMouseWatcherObserver, + public ui::AnimationDelegate { + public: + typedef std::vector<Panel*> Panels; + + explicit PanelOverflowStrip(PanelManager* panel_manager); + virtual ~PanelOverflowStrip(); + + // Sets the display area of the overflow strip. + // |display_area| is in screen coordinates. + void SetDisplayArea(const gfx::Rect& display_area); + + // Adds a panel to the strip. |is_new| indicates if the panel is a newly + // created panel or one that is transitioning from another grouping of panels. + void AddPanel(Panel* panel, bool is_new); + + // Returns |false| if the panel is not in the strip. + bool Remove(Panel* panel); + void RemoveAll(); + + // Called when a panel's expansion state changes. + void OnPanelExpansionStateChanged( + Panel* panel, Panel::ExpansionState old_state); + + // Refreshes the layouts for all panels to reflect any possible changes. + void Refresh(); + + void OnFullScreenModeChanged(bool is_full_screen); + + int num_panels() const { return static_cast<int>(panels_.size()); } + Panel* first_panel() const { + return panels_.empty() ? NULL : panels_.front(); + } + +#ifdef UNIT_TEST + const Panels& panels() const { return panels_; } +#endif + + private: + // Overridden from PanelMouseWatcherObserver: + virtual void OnMouseMove(const gfx::Point& mouse_position) OVERRIDE; + + // Overridden from AnimationDelegate: + virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; + + void DoRefresh(size_t start_index, size_t end_index); + + // Computes the layout of the |index| panel to fit into the area. + // Empty bounds will be returned if this is not possible due to not enough + // space. + gfx::Rect ComputeLayout(size_t index, + const gfx::Size& iconified_size) const; + + // Used to pop up the titles for overflow panels when the mouse hovers over + // the overflow area. + bool ShouldShowOverflowTitles(const gfx::Point& mouse_position) const; + void ShowOverflowTitles(bool show_overflow_titles); + + // Weak pointer since PanelManager owns PanelOverflowStrip instance. + PanelManager* panel_manager_; + + // The queue for storing all panels. + Panels panels_; + + // The overflow area where panels are iconified due to insufficient space + // in the panel strip. + gfx::Rect display_area_; + + // For mouse hover-over effect. + bool are_overflow_titles_shown_; + scoped_ptr<ui::SlideAnimation> overflow_hover_animator_; + int overflow_hover_animator_start_width_; + int overflow_hover_animator_end_width_; + + // Invalid panel index. + static const size_t kInvalidPanelIndex = static_cast<size_t>(-1); + + DISALLOW_COPY_AND_ASSIGN(PanelOverflowStrip); +}; + +#endif // CHROME_BROWSER_UI_PANELS_PANEL_OVERFLOW_STRIP_H_ diff --git a/chrome/browser/ui/panels/panel_strip.cc b/chrome/browser/ui/panels/panel_strip.cc index e94c157..499516f 100644 --- a/chrome/browser/ui/panels/panel_strip.cc +++ b/chrome/browser/ui/panels/panel_strip.cc @@ -12,6 +12,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/panels/panel_manager.h" #include "chrome/browser/ui/panels/panel_mouse_watcher.h" +#include "chrome/browser/ui/panels/panel_overflow_strip.h" #include "chrome/common/chrome_notification_types.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" @@ -73,13 +74,10 @@ void PanelStrip::SetDisplayArea(const gfx::Rect& new_area) { gfx::Rect old_area = display_area_; display_area_ = new_area; - if (panels_.empty() || new_area.width() == old_area.width()) + if (panels_.empty()) return; - if (new_area.width() < old_area.width()) - Rearrange(); - else - MovePanelsFromOverflowIfNeeded(); + Rearrange(); } void PanelStrip::AddPanel(Panel* panel) { @@ -132,6 +130,9 @@ void PanelStrip::AddPanel(Panel* panel) { // Keep panel visible in the strip even if overlap would occur. // Panel is moved to overflow from the strip after a delay. + // TODO(jianli): remove the guard when overflow support is enabled on other + // platforms. http://crbug.com/105073 +#if defined(OS_WIN) if (x < display_area_.x()) { x = display_area_.x(); int delay_ms = remove_delays_for_testing_ ? 0 : @@ -144,6 +145,7 @@ void PanelStrip::AddPanel(Panel* panel) { true), // new panel delay_ms); } +#endif panel->Initialize(gfx::Rect(x, y, width, height)); } @@ -334,20 +336,36 @@ void PanelStrip::EndDragging(bool cancelled) { } void PanelStrip::OnPanelExpansionStateChanged( - Panel::ExpansionState old_state, Panel::ExpansionState new_state) { - DCHECK_NE(new_state, old_state); - switch (new_state) { + Panel* panel, Panel::ExpansionState old_state) { + gfx::Size size = panel->restored_size(); + Panel::ExpansionState expansion_state = panel->expansion_state(); + switch (expansion_state) { case Panel::EXPANDED: - DecrementMinimizedPanels(); + if (old_state == Panel::TITLE_ONLY || old_state == Panel::MINIMIZED) + DecrementMinimizedPanels(); break; - case Panel::MINIMIZED: case Panel::TITLE_ONLY: + size.set_height(panel->TitleOnlyHeight()); + if (old_state == Panel::EXPANDED) + IncrementMinimizedPanels(); + break; + case Panel::MINIMIZED: + size.set_height(Panel::kMinimizedPanelHeight); if (old_state == Panel::EXPANDED) IncrementMinimizedPanels(); break; default: + NOTREACHED(); break; } + + int bottom = GetBottomPositionForExpansionState(expansion_state); + gfx::Rect bounds = panel->GetBounds(); + panel->SetPanelBounds( + gfx::Rect(bounds.right() - size.width(), + bottom - size.height(), + size.width(), + size.height())); } void PanelStrip::IncrementMinimizedPanels() { @@ -573,12 +591,16 @@ void PanelStrip::Rearrange() { gfx::Rect new_bounds(panel->GetBounds()); int x = rightmost_position - new_bounds.width(); + // TODO(jianli): remove the guard when overflow support is enabled on other + // platforms. http://crbug.com/105073 +#if defined(OS_WIN) if (x < display_area_.x()) { MovePanelsToOverflow(panel_index); break; } +#endif - new_bounds.set_x(rightmost_position - new_bounds.width()); + new_bounds.set_x(x); new_bounds.set_y( GetBottomPositionForExpansionState(panel->expansion_state()) - new_bounds.height()); @@ -587,8 +609,12 @@ void PanelStrip::Rearrange() { rightmost_position = new_bounds.x() - kPanelsHorizontalSpacing; } + // TODO(jianli): remove the guard when overflow support is enabled on other + // platforms. http://crbug.com/105073 +#if defined(OS_WIN) if (panel_index == panels_.size()) MovePanelsFromOverflowIfNeeded(); +#endif } void PanelStrip::MovePanelsToOverflow(size_t overflow_point) { @@ -602,20 +628,18 @@ void PanelStrip::MovePanelToOverflow(Panel* panel, bool is_new) { if (!DoRemove(panel)) return; - // TODO(jianli): Replace with the real code using overflow strip. - // panel_manager_->panel_overflow_strip()->AddPanel(panel, is_new); + panel_manager_->panel_overflow_strip()->AddPanel(panel, is_new); } void PanelStrip::MovePanelsFromOverflowIfNeeded() { - // TODO(jianli): Replace with the real code using overflow strip. - // PanelOverflowStrip* overflow = panel_manager_->panel_overflow_strip(); - // Panel* candidate; - // while (candidate = overflow->FirstPanel() && - // GetRightMostAvailablePosition - - // candidate->GetRestoredSize().width() >= display_area_.x()) { - // overflow->Remove(candidate); - // AddPanel(candidate); - // } + PanelOverflowStrip* overflow_strip = panel_manager_->panel_overflow_strip(); + Panel* overflow_panel; + while ((overflow_panel = overflow_strip->first_panel()) && + GetRightMostAvailablePosition() - + overflow_panel->restored_size().width() >= display_area_.x()) { + overflow_strip->Remove(overflow_panel); + AddPanel(overflow_panel); + } } void PanelStrip::RemoveAll() { diff --git a/chrome/browser/ui/panels/panel_strip.h b/chrome/browser/ui/panels/panel_strip.h index bdf4655..992e565 100644 --- a/chrome/browser/ui/panels/panel_strip.h +++ b/chrome/browser/ui/panels/panel_strip.h @@ -10,8 +10,8 @@ #include "base/basictypes.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ui/panels/auto_hiding_desktop_bar.h" -#include "chrome/browser/ui/panels/panel_mouse_watcher_observer.h" #include "chrome/browser/ui/panels/panel.h" +#include "chrome/browser/ui/panels/panel_mouse_watcher_observer.h" #include "ui/gfx/rect.h" class Browser; @@ -29,7 +29,7 @@ class PanelStrip : public PanelMouseWatcherObserver { virtual ~PanelStrip(); // Sets the bounds of the panel strip. - // |bounds| is in screen coordinates. + // |area| is in screen coordinates. void SetDisplayArea(const gfx::Rect& area); // Adds a panel to the strip. The panel may be a newly created panel or one @@ -46,8 +46,8 @@ class PanelStrip : public PanelMouseWatcherObserver { void EndDragging(bool cancelled); // Invoked when a panel's expansion state changes. - void OnPanelExpansionStateChanged(Panel::ExpansionState old_state, - Panel::ExpansionState new_state); + void OnPanelExpansionStateChanged(Panel* panel, + Panel::ExpansionState old_state); // Invoked when the preferred window size of the given panel might need to // get changed. @@ -70,14 +70,12 @@ class PanelStrip : public PanelMouseWatcherObserver { int num_panels() const { return panels_.size(); } bool is_dragging_panel() const; const Panels& panels() const { return panels_; } + gfx::Rect display_area() const { return display_area_; } int GetMaxPanelWidth() const; int GetMaxPanelHeight() const; int StartingRightPosition() const; - // Overridden from PanelMouseWatcherObserver: - virtual void OnMouseMove(const gfx::Point& mouse_position) OVERRIDE; - void OnAutoHidingDesktopBarVisibilityChanged( AutoHidingDesktopBar::Alignment alignment, AutoHidingDesktopBar::Visibility visibility); @@ -103,6 +101,9 @@ class PanelStrip : public PanelMouseWatcherObserver { BRING_DOWN }; + // Overridden from PanelMouseWatcherObserver: + virtual void OnMouseMove(const gfx::Point& mouse_position) OVERRIDE; + // Keep track of the minimized panels to control mouse watching. void IncrementMinimizedPanels(); void DecrementMinimizedPanels(); |