diff options
author | twiz@google.com <twiz@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-20 01:08:17 +0000 |
---|---|---|
committer | twiz@google.com <twiz@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-20 01:08:17 +0000 |
commit | 9d7c69e5006a874d7f127db46bdb0e76aaa60ec7 (patch) | |
tree | 6800bce34fb919c11246d7492a190ee739216a36 /chrome/browser | |
parent | 074248931d91c43c612ee611342a5c354f580b2e (diff) | |
download | chromium_src-9d7c69e5006a874d7f127db46bdb0e76aaa60ec7.zip chromium_src-9d7c69e5006a874d7f127db46bdb0e76aaa60ec7.tar.gz chromium_src-9d7c69e5006a874d7f127db46bdb0e76aaa60ec7.tar.bz2 |
Simple change that re-positions the arrow location on displayed extension popup views. This change allows popups to re-orient themselves if they are partially clipped by the working monitor. Note that this only applies to popups created via the experimental extension popup API.
BUG=42779
TEST=None
Review URL: http://codereview.chromium.org/1774012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47760 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/extensions/extension_popup_api.cc | 70 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_popup.cc | 66 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_popup.h | 23 |
3 files changed, 129 insertions, 30 deletions
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc index 6dbae99..acc47e3 100644 --- a/chrome/browser/extensions/extension_popup_api.cc +++ b/chrome/browser/extensions/extension_popup_api.cc @@ -16,6 +16,7 @@ #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/window_sizer.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_service.h" @@ -25,6 +26,7 @@ #include "gfx/point.h" #if defined(TOOLKIT_VIEWS) +#include "chrome/browser/views/bubble_border.h" #include "chrome/browser/views/extensions/extension_popup.h" #include "views/view.h" #include "views/focus/focus_manager.h" @@ -58,6 +60,35 @@ const wchar_t kBorderStyleKey[] = L"borderStyle"; // chrome enumeration values const char kRectangleChrome[] = "rectangle"; +#if defined(TOOLKIT_VIEWS) +// Returns an updated arrow location, conditioned on the type of intersection +// between the popup window, and the screen. |location| is the current position +// of the arrow on the popup. |intersection| is the rect representing the +// intersection between the popup view and its working screen. |popup_rect| +// is the rect of the popup window in screen space coordinates. +// The returned location will be horizontally or vertically inverted based on +// if the popup has been clipped horizontally or vertically. +BubbleBorder::ArrowLocation ToggleArrowLocation( + BubbleBorder::ArrowLocation location, const gfx::Rect& intersection, + const gfx::Rect& popup_rect) { + // If the popup has been clipped horizontally, flip the right-left position + // of the arrow. + if (intersection.right() != popup_rect.right() || + intersection.x() != popup_rect.x()) { + location = BubbleBorder::horizontal_mirror(location); + } + + // If the popup has been clipped vertically, flip the bottom-top position + // of the arrow. + if (intersection.y() != popup_rect.y() || + intersection.bottom() != popup_rect.bottom()) { + location = BubbleBorder::vertical_mirror(location); + } + + return location; +} +#endif // TOOLKIT_VIEWS + }; // namespace #if defined(TOOLKIT_VIEWS) @@ -124,6 +155,45 @@ class ExtensionPopupHost : public ExtensionPopup::Observer, router->RegisterRenderViewHost(host->render_view_host()); } + virtual void ExtensionPopupResized(ExtensionPopup* popup) { + // Reposition the location of the arrow on the popup so that the popup + // better fits on the working monitor. + gfx::Rect popup_rect = popup->GetOuterBounds(); + if (popup_rect.IsEmpty()) + return; + + scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( + WindowSizer::CreateDefaultMonitorInfoProvider()); + gfx::Rect monitor_bounds( + monitor_provider->GetMonitorWorkAreaMatching(popup_rect)); + gfx::Rect intersection = monitor_bounds.Intersect(popup_rect); + + // If the popup is totally out of the bounds of the monitor, then toggling + // the arrow location will not result in an un-clipped window. + if (intersection.IsEmpty()) + return; + + if (!intersection.Equals(popup_rect)) { + // The popup was clipped by the monitor. Toggle the arrow position + // to see if that improves visibility. Note: The assignment and + // re-assignment of the arrow-position will not trigger an intermittent + // display. + BubbleBorder::ArrowLocation previous_location = popup->arrow_position(); + BubbleBorder::ArrowLocation flipped_location = ToggleArrowLocation( + previous_location, intersection, popup_rect); + popup->SetArrowPosition(flipped_location); + + // Double check that toggling the position actually improved the + // situation - the popup will be contained entirely in its working monitor + // bounds. + gfx::Rect flipped_bounds = popup->GetOuterBounds(); + gfx::Rect updated_monitor_bounds = + monitor_provider->GetMonitorWorkAreaMatching(flipped_bounds); + if (!updated_monitor_bounds.Contains(flipped_bounds)) + popup->SetArrowPosition(previous_location); + } + } + virtual void DispatchPopupClosedEvent() { PopupEventRouter::OnPopupClosed( dispatcher_->profile(), dispatcher_->render_view_host()->routing_id()); diff --git a/chrome/browser/views/extensions/extension_popup.cc b/chrome/browser/views/extensions/extension_popup.cc index f30aac9..b3c4b23 100644 --- a/chrome/browser/views/extensions/extension_popup.cc +++ b/chrome/browser/views/extensions/extension_popup.cc @@ -41,11 +41,15 @@ const int ExtensionPopup::kMinHeight = 25; const int ExtensionPopup::kMaxWidth = 800; const int ExtensionPopup::kMaxHeight = 600; +namespace { + // The width, in pixels, of the black-border on a popup. const int kPopupBorderWidth = 1; const int kPopupBubbleCornerRadius = BubbleBorder::GetCornerRadius() / 2; +} // namespace + ExtensionPopup::ExtensionPopup(ExtensionHost* host, views::Widget* frame, const gfx::Rect& relative_to, @@ -138,6 +142,16 @@ ExtensionPopup::~ExtensionPopup() { border_widget_->Close(); } +void ExtensionPopup::SetArrowPosition( + BubbleBorder::ArrowLocation arrow_location) { + DCHECK_NE(BubbleBorder::NONE, arrow_location) << + "Extension popups must be positioned relative to an arrow."; + + anchor_position_ = arrow_location; + if (border_) + border_->set_arrow_location(anchor_position_); +} + void ExtensionPopup::Hide() { BrowserBubble::Hide(); if (border_widget_) @@ -162,19 +176,14 @@ void ExtensionPopup::Show(bool activate) { } void ExtensionPopup::ResizeToView() { - // We'll be sizing ourselves to this size shortly, but wait until we - // know our position to do it. - gfx::Size new_size = view()->size(); + if (observer_) + observer_->ExtensionPopupResized(this); - // Convert rect to screen coordinates. - gfx::Rect rect = relative_to_; - gfx::Point origin = rect.origin(); - views::View::ConvertPointToScreen(frame_->GetRootView(), &origin); - rect.set_origin(origin); + gfx::Rect rect = GetOuterBounds(); - rect = GetOuterBounds(rect, new_size); - origin = rect.origin(); + gfx::Point origin = rect.origin(); views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin); + if (border_widget_) { // Set the bubble-chrome widget according to the outer bounds of the entire // popup. @@ -189,6 +198,7 @@ void ExtensionPopup::ResizeToView() { origin.set_x(origin.x() + border_insets.left() + kPopupBubbleCornerRadius); origin.set_y(origin.y() + border_insets.top() + kPopupBubbleCornerRadius); + gfx::Size new_size = view()->size(); SetBounds(origin.x(), origin.y(), new_size.width(), new_size.height()); } else { SetBounds(origin.x(), origin.y(), rect.width(), rect.height()); @@ -296,8 +306,14 @@ void ExtensionPopup::OnExtensionPreferredSizeChanged(ExtensionView* view) { ResizeToView(); } -gfx::Rect ExtensionPopup::GetOuterBounds(const gfx::Rect& position_relative_to, - const gfx::Size& contents_size) const { +gfx::Rect ExtensionPopup::GetOuterBounds() const { + gfx::Rect relative_rect = relative_to_; + gfx::Point origin = relative_rect.origin(); + views::View::ConvertPointToScreen(frame_->GetRootView(), &origin); + relative_rect.set_origin(origin); + + gfx::Size contents_size = view()->size(); + // If the popup has a bubble-chrome, then let the BubbleBorder compute // the bounds. if (BUBBLE_CHROME == popup_chrome_) { @@ -305,23 +321,25 @@ gfx::Rect ExtensionPopup::GetOuterBounds(const gfx::Rect& position_relative_to, // claim. Since we can't clip the ExtensionView's corners, we need to // increase the inset by half the corner radius as well as lying about the // size of the contents size to compensate. - gfx::Size adjusted_size = contents_size; - adjusted_size.Enlarge(2 * kPopupBubbleCornerRadius, + contents_size.Enlarge(2 * kPopupBubbleCornerRadius, 2 * kPopupBubbleCornerRadius); - return border_->GetBounds(position_relative_to, adjusted_size); + return border_->GetBounds(relative_rect, contents_size); } // Position the bounds according to the location of the |anchor_position_|. int y; - if ((anchor_position_ == BubbleBorder::TOP_LEFT) || - (anchor_position_ == BubbleBorder::TOP_RIGHT)) { - y = position_relative_to.bottom(); - } else { - y = position_relative_to.y() - contents_size.height(); - } - - return gfx::Rect(position_relative_to.x(), y, contents_size.width(), - contents_size.height()); + if (BubbleBorder::is_arrow_on_top(anchor_position_)) + y = relative_rect.bottom(); + else + y = relative_rect.y() - contents_size.height(); + + int x; + if (BubbleBorder::is_arrow_on_left(anchor_position_)) + x = relative_rect.x(); + else + x = relative_rect.x() - contents_size.width(); + + return gfx::Rect(x, y, contents_size.width(), contents_size.height()); } // static diff --git a/chrome/browser/views/extensions/extension_popup.h b/chrome/browser/views/extensions/extension_popup.h index 5c62b5d..aafe5d1 100644 --- a/chrome/browser/views/extensions/extension_popup.h +++ b/chrome/browser/views/extensions/extension_popup.h @@ -43,6 +43,11 @@ class ExtensionPopup : public BrowserBubble, // into the popup. An example use is for automation resource routing in // Chrome-Frame. See extension_popup_api.cc. virtual void ExtensionHostCreated(ExtensionHost* host) {} + + // Called when the ExtensionPopup is resized. Note that the popup may have + // an empty bounds, if a popup is repositioned before the hosted content + // has loaded. + virtual void ExtensionPopupResized(ExtensionPopup* popup) {} }; enum PopupChrome { @@ -100,6 +105,18 @@ class ExtensionPopup : public BrowserBubble, ExtensionHost* host() const { return extension_host_.get(); } + // Assigns the arrow location of the popup view, and updates the popup + // border widget, if necessary. + void SetArrowPosition(BubbleBorder::ArrowLocation arrow_location); + BubbleBorder::ArrowLocation arrow_position() const { + return anchor_position_; + } + + // Gives the desired bounds (in screen coordinates) given the rect to point + // to and the size of the contained contents. Includes all of the + // border-chrome surrounding the pop-up as well. + gfx::Rect GetOuterBounds() const; + // BrowserBubble overrides. virtual void Hide(); virtual void Show(bool activate); @@ -138,12 +155,6 @@ class ExtensionPopup : public BrowserBubble, PopupChrome chrome, Observer* observer); - // Gives the desired bounds (in screen coordinates) given the rect to point - // to and the size of the contained contents. Includes all of the - // border-chrome surrounding the pop-up as well. - gfx::Rect GetOuterBounds(const gfx::Rect& position_relative_to, - const gfx::Size& contents_size) const; - // The area on the screen that the popup should be positioned relative to. gfx::Rect relative_to_; |