1999-07-18 06:23:45 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
1999-07-18 06:23:45 +00:00
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
1999-07-18 06:23:45 +00:00
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1999-07-18 06:23:45 +00:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-06 03:40:37 +00:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
2000-03-21 13:24:48 +00:00
|
|
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* Contributor(s):
|
2000-03-23 21:10:09 +00:00
|
|
|
* Mike Pinkerton (pinkerton@netscape.com)
|
2000-03-01 03:12:51 +00:00
|
|
|
* Dean Tessman <dean_tessman@hotmail.com>
|
1999-07-18 06:23:45 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "nsMenuPopupFrame.h"
|
1999-07-20 07:28:39 +00:00
|
|
|
#include "nsXULAtoms.h"
|
1999-07-20 09:50:48 +00:00
|
|
|
#include "nsHTMLAtoms.h"
|
1999-07-18 06:23:45 +00:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "prtypes.h"
|
|
|
|
#include "nsIAtom.h"
|
|
|
|
#include "nsIPresContext.h"
|
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
#include "nsCSSRendering.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
1999-07-20 08:37:03 +00:00
|
|
|
#include "nsIViewManager.h"
|
|
|
|
#include "nsWidgetsCID.h"
|
1999-07-22 09:01:55 +00:00
|
|
|
#include "nsMenuFrame.h"
|
1999-09-21 01:03:00 +00:00
|
|
|
#include "nsIPopupSetFrame.h"
|
1999-11-23 03:02:01 +00:00
|
|
|
#include "nsIDOMWindow.h"
|
|
|
|
#include "nsIDOMScreen.h"
|
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIScriptObjectOwner.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIDeviceContext.h"
|
|
|
|
#include "nsRect.h"
|
2000-02-08 09:30:15 +00:00
|
|
|
#include "nsIDOMXULDocument.h"
|
2000-02-13 08:33:39 +00:00
|
|
|
#include "nsILookAndFeel.h"
|
|
|
|
#include "nsIComponentManager.h"
|
2000-02-08 09:30:15 +00:00
|
|
|
|
1999-07-20 08:37:03 +00:00
|
|
|
|
2000-02-13 08:33:39 +00:00
|
|
|
static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
|
|
|
|
static NS_DEFINE_IID(kILookAndFeelIID, NS_ILOOKANDFEEL_IID);
|
|
|
|
|
1999-07-20 08:37:03 +00:00
|
|
|
const PRInt32 kMaxZ = 0x7fffffff; //XXX: Shouldn't there be a define somewhere for MaxInt for PRInt32
|
1999-07-18 06:23:45 +00:00
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID);
|
1999-07-18 06:23:45 +00:00
|
|
|
|
|
|
|
// NS_NewMenuPopupFrame
|
|
|
|
//
|
|
|
|
// Wrapper for creating a new menu popup container
|
|
|
|
//
|
|
|
|
nsresult
|
1999-12-04 23:49:50 +00:00
|
|
|
NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
|
1999-07-18 06:23:45 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
|
|
if (nsnull == aNewFrame) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
2000-03-02 03:01:30 +00:00
|
|
|
nsMenuPopupFrame* it = new (aPresShell) nsMenuPopupFrame (aPresShell);
|
1999-07-18 06:23:45 +00:00
|
|
|
if ( !it )
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
*aNewFrame = it;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
NS_IMETHODIMP_(nsrefcnt)
|
|
|
|
nsMenuPopupFrame::AddRef(void)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(nsrefcnt)
|
|
|
|
nsMenuPopupFrame::Release(void)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-12-22 01:57:29 +00:00
|
|
|
//
|
|
|
|
// QueryInterface
|
|
|
|
//
|
1999-12-21 19:28:15 +00:00
|
|
|
NS_INTERFACE_MAP_BEGIN(nsMenuPopupFrame)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIMenuParent)
|
2000-02-13 08:33:39 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
2000-01-26 22:35:53 +00:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
|
|
|
|
|
1999-07-18 06:23:45 +00:00
|
|
|
|
|
|
|
//
|
2000-03-01 03:12:51 +00:00
|
|
|
// nsMenuPopupFrame ctor
|
1999-07-18 06:23:45 +00:00
|
|
|
//
|
2000-03-23 21:10:09 +00:00
|
|
|
nsMenuPopupFrame::nsMenuPopupFrame(nsIPresShell* aShell)
|
|
|
|
:nsBoxFrame(aShell), mCurrentMenu(nsnull), mTimerMenu(nsnull), mCloseTimer(nsnull),
|
|
|
|
mMenuCanOverlapOSBar(PR_FALSE)
|
1999-07-18 06:23:45 +00:00
|
|
|
{
|
2000-03-01 03:12:51 +00:00
|
|
|
SetIsContextMenu(PR_FALSE); // we're not a context menu by default
|
|
|
|
|
|
|
|
} // ctor
|
1999-07-18 06:23:45 +00:00
|
|
|
|
|
|
|
|
1999-07-20 07:28:39 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsMenuPopupFrame::Init(nsIPresContext* aPresContext,
|
1999-07-20 07:28:39 +00:00
|
|
|
nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aContext,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
1999-07-21 02:56:23 +00:00
|
|
|
nsresult rv = nsBoxFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
|
1999-07-20 09:50:48 +00:00
|
|
|
|
2000-03-23 21:10:09 +00:00
|
|
|
// lookup if we're allowed to overlap the OS bar (menubar/taskbar) from the
|
|
|
|
// look&feel object
|
|
|
|
nsCOMPtr<nsILookAndFeel> lookAndFeel;
|
|
|
|
nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, kILookAndFeelIID,
|
|
|
|
getter_AddRefs(lookAndFeel));
|
|
|
|
if ( lookAndFeel )
|
|
|
|
lookAndFeel->GetMetric(nsILookAndFeel::eMetric_MenusCanOverlapOSBar, mMenuCanOverlapOSBar);
|
|
|
|
|
1999-10-26 04:44:41 +00:00
|
|
|
// XXX Hack
|
1999-11-24 06:03:41 +00:00
|
|
|
mPresContext = aPresContext;
|
1999-10-26 04:44:41 +00:00
|
|
|
|
1999-07-20 10:35:24 +00:00
|
|
|
CreateViewForFrame(aPresContext, this, aContext, PR_TRUE);
|
1999-07-20 08:37:03 +00:00
|
|
|
|
|
|
|
// Now that we've made a view, remove it and insert it at the correct
|
|
|
|
// position in the view hierarchy (as the root view). We do this so that we
|
|
|
|
// can draw the menus outside the confines of the window.
|
|
|
|
nsIView* ourView;
|
1999-11-24 06:03:41 +00:00
|
|
|
GetView(aPresContext, &ourView);
|
1999-07-20 08:37:03 +00:00
|
|
|
|
|
|
|
nsIFrame* parent;
|
1999-11-24 06:03:41 +00:00
|
|
|
aParent->GetParentWithView(aPresContext, &parent);
|
1999-07-20 08:37:03 +00:00
|
|
|
nsIView* parentView;
|
1999-11-24 06:03:41 +00:00
|
|
|
parent->GetView(aPresContext, &parentView);
|
1999-07-20 08:37:03 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIViewManager> viewManager;
|
|
|
|
parentView->GetViewManager(*getter_AddRefs(viewManager));
|
|
|
|
|
|
|
|
// Remove the view from its old position.
|
|
|
|
viewManager->RemoveChild(parentView, ourView);
|
|
|
|
|
|
|
|
// Reinsert ourselves as the root view with a maximum z-index.
|
|
|
|
nsIView* rootView;
|
|
|
|
viewManager->GetRootView(rootView);
|
|
|
|
viewManager->InsertChild(rootView, ourView, kMaxZ);
|
|
|
|
|
2000-01-25 01:53:34 +00:00
|
|
|
// XXX Hack. The menu's view should float above all other views,
|
|
|
|
// so we use the nsIView::SetFloating() to tell the view manager
|
|
|
|
// about that constraint.
|
|
|
|
ourView->SetFloating(PR_TRUE);
|
|
|
|
|
1999-07-31 01:43:33 +00:00
|
|
|
// XXX Hack. Change our transparency to be non-transparent
|
|
|
|
// until the bug related to update of transparency on show/hide
|
|
|
|
// is fixed.
|
|
|
|
viewManager->SetViewContentTransparency(ourView, PR_FALSE);
|
|
|
|
|
1999-07-20 08:37:03 +00:00
|
|
|
// Create a widget for ourselves.
|
|
|
|
nsWidgetInitData widgetData;
|
|
|
|
ourView->SetZIndex(kMaxZ);
|
1999-07-27 04:27:17 +00:00
|
|
|
widgetData.mWindowType = eWindowType_popup;
|
|
|
|
widgetData.mBorderStyle = eBorderStyle_default;
|
1999-09-26 22:45:35 +00:00
|
|
|
|
1999-09-28 23:25:48 +00:00
|
|
|
// XXX make sure we are hidden (shouldn't this be done automatically?)
|
|
|
|
ourView->SetVisibility(nsViewVisibility_kHide);
|
1999-09-26 22:45:35 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
printf("XP Popups: This is a nag to indicate that an inconsistent hack is being done on the Mac for popups.\n");
|
|
|
|
static NS_DEFINE_IID(kCPopupCID, NS_POPUP_CID);
|
|
|
|
ourView->CreateWidget(kCPopupCID, &widgetData, nsnull);
|
|
|
|
#else
|
1999-07-20 08:37:03 +00:00
|
|
|
static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
|
1999-09-26 22:45:35 +00:00
|
|
|
ourView->CreateWidget(kCChildCID, &widgetData, nsnull);
|
|
|
|
#endif
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
return rv;
|
1999-07-20 07:28:39 +00:00
|
|
|
}
|
1999-07-20 09:35:35 +00:00
|
|
|
|
2000-04-25 07:10:48 +00:00
|
|
|
void
|
|
|
|
nsMenuPopupFrame::GetLayoutFlags(PRUint32& aFlags)
|
|
|
|
{
|
|
|
|
aFlags = NS_FRAME_NO_SIZE_VIEW | NS_FRAME_NO_MOVE_VIEW | NS_FRAME_NO_MOVE_CHILD_VIEWS;
|
|
|
|
}
|
|
|
|
|
1999-11-18 21:05:43 +00:00
|
|
|
PRBool
|
2000-02-14 01:42:09 +00:00
|
|
|
nsMenuPopupFrame::GetInitialOrientation(PRBool& aIsHorizontal)
|
1999-11-18 21:05:43 +00:00
|
|
|
{
|
2000-02-14 01:42:09 +00:00
|
|
|
// by default we are vertical
|
|
|
|
aIsHorizontal = PR_FALSE;
|
|
|
|
return nsBoxFrame::GetInitialOrientation(aIsHorizontal);
|
1999-11-18 21:05:43 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
void
|
|
|
|
nsMenuPopupFrame::GetViewOffset(nsIViewManager* aManager, nsIView* aView,
|
|
|
|
nsPoint& aPoint)
|
|
|
|
{
|
|
|
|
aPoint.x = 0;
|
|
|
|
aPoint.y = 0;
|
|
|
|
|
|
|
|
nsIView *parent;
|
|
|
|
nsRect bounds;
|
|
|
|
|
|
|
|
parent = aView;
|
|
|
|
while (nsnull != parent) {
|
|
|
|
parent->GetBounds(bounds);
|
|
|
|
aPoint.x += bounds.x;
|
|
|
|
aPoint.y += bounds.y;
|
|
|
|
parent->GetParent(parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-09-10 08:47:12 +00:00
|
|
|
void
|
1999-10-26 04:44:41 +00:00
|
|
|
nsMenuPopupFrame::GetNearestEnclosingView(nsIPresContext* aPresContext, nsIFrame* aStartFrame, nsIView** aResult)
|
1999-09-10 08:47:12 +00:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
1999-10-26 04:44:41 +00:00
|
|
|
aStartFrame->GetView(aPresContext, aResult);
|
1999-09-10 08:47:12 +00:00
|
|
|
if (!*aResult) {
|
|
|
|
nsIFrame* parent;
|
1999-10-26 04:44:41 +00:00
|
|
|
aStartFrame->GetParentWithView(aPresContext, &parent);
|
1999-09-10 08:47:12 +00:00
|
|
|
if (parent)
|
1999-10-26 04:44:41 +00:00
|
|
|
parent->GetView(aPresContext, aResult);
|
1999-09-10 08:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-04 07:44:43 +00:00
|
|
|
|
|
|
|
void GetWidgetForView(nsIView *aView, nsIWidget *&aWidget);
|
|
|
|
void GetWidgetForView(nsIView *aView, nsIWidget *&aWidget)
|
|
|
|
{
|
|
|
|
aWidget = nsnull;
|
|
|
|
nsIView *view = aView;
|
|
|
|
while (!aWidget && view)
|
|
|
|
{
|
|
|
|
view->GetWidget(aWidget);
|
|
|
|
if (!aWidget)
|
|
|
|
view->GetParent(view);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-02-08 09:30:15 +00:00
|
|
|
//
|
|
|
|
// AdjustClientXYForNestedDocuments
|
|
|
|
//
|
|
|
|
// almost certainly, the document where the mouse was clicked is not
|
|
|
|
// the document that contains the popup, especially if we're viewing a page
|
|
|
|
// with frames. Thus we need to make adjustments to the client coordinates to
|
|
|
|
// take this into account and get them back into the relative coordinates of
|
|
|
|
// this document.
|
|
|
|
//
|
|
|
|
void
|
|
|
|
nsMenuPopupFrame :: AdjustClientXYForNestedDocuments ( nsIDOMXULDocument* inPopupDoc, nsIPresShell* inPopupShell,
|
|
|
|
PRInt32 inClientX, PRInt32 inClientY,
|
|
|
|
PRInt32* outAdjX, PRInt32* outAdjY )
|
|
|
|
{
|
|
|
|
if ( !inPopupDoc || !outAdjX || !outAdjY )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Find the widget associated with the popup's document
|
|
|
|
nsCOMPtr<nsIWidget> popupDocumentWidget;
|
|
|
|
nsCOMPtr<nsIViewManager> viewManager;
|
|
|
|
inPopupShell->GetViewManager(getter_AddRefs(viewManager));
|
|
|
|
nsIView* rootView;
|
|
|
|
viewManager->GetRootView(rootView);
|
|
|
|
nscoord wOffsetX, wOffsetY;
|
|
|
|
rootView->GetOffsetFromWidget(&wOffsetX, &wOffsetY, *getter_AddRefs(popupDocumentWidget));
|
|
|
|
NS_WARN_IF_FALSE(popupDocumentWidget, "ACK, BAD WIDGET");
|
|
|
|
|
|
|
|
// Find the widget associated with the target's document. Recall that we cached the
|
|
|
|
// target popup node in the document of the popup in the nsXULPopupListener.
|
|
|
|
nsCOMPtr<nsIDOMNode> targetNode;
|
|
|
|
inPopupDoc->GetPopupNode(getter_AddRefs(targetNode));
|
|
|
|
NS_WARN_IF_FALSE(targetNode, "ACK, BAD TARGET NODE");
|
|
|
|
nsCOMPtr<nsIContent> targetAsContent ( do_QueryInterface(targetNode) );
|
|
|
|
nsCOMPtr<nsIWidget> targetDocumentWidget;
|
|
|
|
if ( targetAsContent ) {
|
|
|
|
nsCOMPtr<nsIDocument> targetDocument;
|
|
|
|
targetAsContent->GetDocument(*getter_AddRefs(targetDocument));
|
2000-04-25 01:44:53 +00:00
|
|
|
if (targetDocument) {
|
|
|
|
nsCOMPtr<nsIPresShell> shell ( dont_AddRef(targetDocument->GetShellAt(0)) );
|
|
|
|
nsCOMPtr<nsIViewManager> viewManagerTarget;
|
|
|
|
shell->GetViewManager(getter_AddRefs(viewManagerTarget));
|
|
|
|
nsIView* rootViewTarget;
|
|
|
|
viewManagerTarget->GetRootView(rootViewTarget);
|
|
|
|
nscoord unusedX, unusedY;
|
|
|
|
rootViewTarget->GetOffsetFromWidget(&unusedX, &unusedY, *getter_AddRefs(targetDocumentWidget));
|
|
|
|
}
|
2000-02-08 09:30:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// the offset we need is the difference between the upper left corner of the two widgets. Use
|
|
|
|
// screen coordinates to find the global offset between them.
|
|
|
|
nsRect popupDocTopLeft;
|
|
|
|
if ( popupDocumentWidget ) {
|
|
|
|
nsRect topLeftClient ( 0, 0, 10, 10 );
|
|
|
|
popupDocumentWidget->WidgetToScreen ( topLeftClient, popupDocTopLeft );
|
|
|
|
}
|
|
|
|
nsRect targetDocTopLeft;
|
|
|
|
if ( targetDocumentWidget ) {
|
|
|
|
nsRect topLeftClient ( 0, 0, 10, 10 );
|
|
|
|
targetDocumentWidget->WidgetToScreen ( topLeftClient, targetDocTopLeft );
|
|
|
|
}
|
|
|
|
nsPoint pixelOffset ( targetDocTopLeft.x - popupDocTopLeft.x, targetDocTopLeft.y - popupDocTopLeft.y );
|
|
|
|
|
|
|
|
*outAdjX = inClientX + pixelOffset.x;
|
|
|
|
*outAdjY = inClientY + pixelOffset.y;
|
|
|
|
|
|
|
|
} // AdjustClientXYForNestedDocuments
|
|
|
|
|
|
|
|
|
2000-03-02 04:08:04 +00:00
|
|
|
//
|
|
|
|
// AdjustPositionForAnchorAlign
|
|
|
|
//
|
|
|
|
// Uses the |popupanchor| and |popupalign| attributes on the popup to move the popup around and
|
|
|
|
// anchor it to its parent. |outFlushWithTopBottom| will be TRUE if the popup is flush with either
|
|
|
|
// the top or bottom edge of its parent, and FALSE if it is flush with the left or right edge of
|
|
|
|
// the parent.
|
|
|
|
//
|
|
|
|
void
|
|
|
|
nsMenuPopupFrame :: AdjustPositionForAnchorAlign ( PRInt32* ioXPos, PRInt32* ioYPos, const nsRect & inParentRect,
|
|
|
|
const nsString& aPopupAnchor, const nsString& aPopupAlign,
|
|
|
|
PRBool* outFlushWithTopBottom )
|
|
|
|
{
|
2000-04-16 11:19:26 +00:00
|
|
|
if (aPopupAnchor.EqualsWithConversion("topright") && aPopupAlign.EqualsWithConversion("topleft")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioXPos += inParentRect.width;
|
|
|
|
}
|
2000-04-16 11:19:26 +00:00
|
|
|
else if (aPopupAnchor.EqualsWithConversion("topright") && aPopupAlign.EqualsWithConversion("bottomright")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioXPos -= (mRect.width - inParentRect.width);
|
|
|
|
*ioYPos -= mRect.height;
|
|
|
|
*outFlushWithTopBottom = PR_TRUE;
|
|
|
|
}
|
2000-04-16 11:19:26 +00:00
|
|
|
else if (aPopupAnchor.EqualsWithConversion("bottomright") && aPopupAlign.EqualsWithConversion("bottomleft")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioXPos += inParentRect.width;
|
|
|
|
*ioYPos -= (mRect.height - inParentRect.height);
|
|
|
|
}
|
2000-04-16 11:19:26 +00:00
|
|
|
else if (aPopupAnchor.EqualsWithConversion("bottomright") && aPopupAlign.EqualsWithConversion("topright")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioXPos -= (mRect.width - inParentRect.width);
|
|
|
|
*ioYPos += inParentRect.height;
|
|
|
|
*outFlushWithTopBottom = PR_TRUE;
|
|
|
|
}
|
2000-04-16 11:19:26 +00:00
|
|
|
else if (aPopupAnchor.EqualsWithConversion("topleft") && aPopupAlign.EqualsWithConversion("topright")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioXPos -= mRect.width;
|
|
|
|
}
|
2000-04-16 11:19:26 +00:00
|
|
|
else if (aPopupAnchor.EqualsWithConversion("topleft") && aPopupAlign.EqualsWithConversion("bottomleft")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioYPos -= mRect.height;
|
|
|
|
*outFlushWithTopBottom = PR_TRUE;
|
|
|
|
}
|
2000-04-16 11:19:26 +00:00
|
|
|
else if (aPopupAnchor.EqualsWithConversion("bottomleft") && aPopupAlign.EqualsWithConversion("bottomright")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioXPos -= mRect.width;
|
|
|
|
*ioYPos -= (mRect.height - inParentRect.height);
|
|
|
|
}
|
2000-04-16 11:19:26 +00:00
|
|
|
else if (aPopupAnchor.EqualsWithConversion("bottomleft") && aPopupAlign.EqualsWithConversion("topleft")) {
|
2000-03-02 04:08:04 +00:00
|
|
|
*ioYPos += inParentRect.height;
|
|
|
|
*outFlushWithTopBottom = PR_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
NS_WARNING ( "Hmmm, looks like you've hit a anchor/align case we weren't setup for." );
|
|
|
|
|
|
|
|
} // AdjustPositionForAnchorAlign
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// IsMoreRoomOnOtherSideOfParent
|
|
|
|
//
|
|
|
|
// Determine if there is more room on the screen for the popup to live if it was positioned
|
|
|
|
// on the flip side of the parent from the side it is flush against (ie, if it's top edge was
|
|
|
|
// flush against the bottom, is there more room if its bottom edge were flush against the top)
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsMenuPopupFrame :: IsMoreRoomOnOtherSideOfParent ( PRBool inFlushAboveBelow, PRInt32 inScreenViewLocX, PRInt32 inScreenViewLocY,
|
|
|
|
const nsRect & inScreenParentFrameRect, PRInt32 inScreenTopTwips, PRInt32 inScreenLeftTwips,
|
|
|
|
PRInt32 inScreenBottomTwips, PRInt32 inScreenRightTwips )
|
|
|
|
{
|
|
|
|
PRBool switchSides = PR_FALSE;
|
|
|
|
if ( inFlushAboveBelow ) {
|
|
|
|
PRInt32 availAbove = inScreenParentFrameRect.y - inScreenTopTwips;
|
|
|
|
PRInt32 availBelow = inScreenBottomTwips - (inScreenParentFrameRect.y + inScreenParentFrameRect.height) ;
|
|
|
|
if ( inScreenViewLocY > inScreenParentFrameRect.y ) // view is now below parent
|
|
|
|
switchSides = availAbove > availBelow;
|
|
|
|
else
|
|
|
|
switchSides = availBelow > availAbove;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PRInt32 availLeft = inScreenParentFrameRect.x - inScreenLeftTwips;
|
|
|
|
PRInt32 availRight = inScreenRightTwips - (inScreenParentFrameRect.x + inScreenParentFrameRect.width) ;
|
|
|
|
if ( inScreenViewLocX > inScreenParentFrameRect.x ) // view is now to the right of parent
|
|
|
|
switchSides = availLeft > availRight;
|
|
|
|
else
|
|
|
|
switchSides = availRight > availLeft;
|
|
|
|
}
|
|
|
|
|
|
|
|
return switchSides;
|
|
|
|
|
|
|
|
} // IsMoreRoomOnOtherSideOfParent
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// MovePopupToOtherSideOfParent
|
|
|
|
//
|
|
|
|
// Move the popup to the other side of the parent (ie, if it the popup's top edge is flush against the
|
|
|
|
// bottom of its parent, move the popup so that its bottom edge is now flush against the top of its
|
|
|
|
// parent...same idea for left/right).
|
|
|
|
//
|
|
|
|
// NOTE: In moving the popup, it may need to change size in order to stay on the screen. This will
|
|
|
|
// have the side effect of touching |mRect|.
|
|
|
|
//
|
|
|
|
void
|
|
|
|
nsMenuPopupFrame :: MovePopupToOtherSideOfParent ( PRBool inFlushAboveBelow, PRInt32* ioXPos, PRInt32* ioYPos,
|
|
|
|
PRInt32* ioScreenViewLocX, PRInt32* ioScreenViewLocY,
|
|
|
|
const nsRect & inScreenParentFrameRect, PRInt32 inScreenTopTwips, PRInt32 inScreenLeftTwips,
|
|
|
|
PRInt32 inScreenBottomTwips, PRInt32 inScreenRightTwips )
|
|
|
|
{
|
|
|
|
if ( inFlushAboveBelow ) {
|
|
|
|
if ( *ioScreenViewLocY > inScreenParentFrameRect.y ) { // view is currently below parent
|
|
|
|
// move it above.
|
|
|
|
PRInt32 shiftDistY = inScreenParentFrameRect.height + mRect.height;
|
|
|
|
*ioYPos -= shiftDistY;
|
|
|
|
*ioScreenViewLocY -= shiftDistY;
|
|
|
|
// trim it to fit.
|
|
|
|
if ( *ioScreenViewLocY < inScreenTopTwips ) {
|
|
|
|
PRInt32 trimY = inScreenTopTwips - *ioScreenViewLocY;
|
|
|
|
*ioYPos += trimY;
|
|
|
|
*ioScreenViewLocY += trimY;
|
|
|
|
mRect.height -= trimY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // view is currently above parent
|
|
|
|
// move it below
|
|
|
|
PRInt32 shiftDistY = inScreenParentFrameRect.height + mRect.height;
|
|
|
|
*ioYPos += shiftDistY;
|
|
|
|
*ioScreenViewLocY += shiftDistY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ( *ioScreenViewLocX > inScreenParentFrameRect.x ) { // view is currently to the right of the parent
|
|
|
|
// move it to the left.
|
|
|
|
PRInt32 shiftDistX = inScreenParentFrameRect.width + mRect.width;
|
|
|
|
*ioXPos -= shiftDistX;
|
|
|
|
*ioScreenViewLocX -= shiftDistX;
|
|
|
|
// trim it to fit.
|
|
|
|
if ( *ioScreenViewLocX < inScreenLeftTwips ) {
|
|
|
|
PRInt32 trimX = inScreenLeftTwips - *ioScreenViewLocX;
|
|
|
|
*ioXPos += trimX;
|
|
|
|
*ioScreenViewLocX += trimX;
|
|
|
|
mRect.width -= trimX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // view is currently to the right of the parent
|
|
|
|
// move it to the right
|
|
|
|
PRInt32 shiftDistX = inScreenParentFrameRect.width + mRect.width;
|
|
|
|
*ioXPos += shiftDistX;
|
|
|
|
*ioScreenViewLocX += shiftDistX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // MovePopupToOtherSideOfParent
|
|
|
|
|
|
|
|
|
2000-02-08 09:30:15 +00:00
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
nsresult
|
1999-11-24 06:03:41 +00:00
|
|
|
nsMenuPopupFrame::SyncViewWithFrame(nsIPresContext* aPresContext,
|
1999-12-08 11:30:47 +00:00
|
|
|
const nsString& aPopupAnchor,
|
|
|
|
const nsString& aPopupAlign,
|
1999-09-10 08:47:12 +00:00
|
|
|
nsIFrame* aFrame,
|
|
|
|
PRInt32 aXPos, PRInt32 aYPos)
|
1999-07-20 09:35:35 +00:00
|
|
|
{
|
1999-11-24 06:03:41 +00:00
|
|
|
NS_ENSURE_ARG(aPresContext);
|
2000-05-12 02:58:21 +00:00
|
|
|
NS_ENSURE_ARG(aFrame);
|
1999-07-20 09:35:35 +00:00
|
|
|
nsPoint parentPos;
|
|
|
|
nsCOMPtr<nsIViewManager> viewManager;
|
|
|
|
|
2000-02-04 07:27:30 +00:00
|
|
|
//
|
|
|
|
// Collect info about our parent view and the frame we're sync'ing to
|
|
|
|
//
|
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
nsIView* parentView = nsnull;
|
1999-11-24 06:03:41 +00:00
|
|
|
GetNearestEnclosingView(aPresContext, aFrame, &parentView);
|
1999-09-10 08:47:12 +00:00
|
|
|
if (!parentView)
|
|
|
|
return NS_OK;
|
1999-07-20 09:35:35 +00:00
|
|
|
|
|
|
|
parentView->GetViewManager(*getter_AddRefs(viewManager));
|
|
|
|
GetViewOffset(viewManager, parentView, parentPos);
|
|
|
|
nsIView* view = nsnull;
|
1999-11-24 06:03:41 +00:00
|
|
|
GetView(aPresContext, &view);
|
1999-07-20 09:35:35 +00:00
|
|
|
|
|
|
|
nsIView* containingView = nsnull;
|
|
|
|
nsPoint offset;
|
1999-11-24 06:03:41 +00:00
|
|
|
aFrame->GetOffsetFromView(aPresContext, offset, &containingView);
|
1999-07-20 09:35:35 +00:00
|
|
|
|
|
|
|
nsRect parentRect;
|
1999-09-10 08:47:12 +00:00
|
|
|
aFrame->GetRect(parentRect);
|
1999-07-20 09:35:35 +00:00
|
|
|
|
1999-11-23 03:02:01 +00:00
|
|
|
float p2t, t2p;
|
1999-11-24 06:03:41 +00:00
|
|
|
aPresContext->GetScaledPixelsToTwips(&p2t);
|
1999-11-23 03:02:01 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDeviceContext> dx;
|
|
|
|
viewManager->GetDeviceContext(*getter_AddRefs(dx));
|
|
|
|
dx->GetAppUnitsToDevUnits(t2p);
|
2000-02-08 09:30:15 +00:00
|
|
|
|
|
|
|
// get the document and the global script object
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
nsCOMPtr<nsIDocument> document;
|
|
|
|
presShell->GetDocument(getter_AddRefs(document));
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> scriptGlobalObject;
|
|
|
|
document->GetScriptGlobalObject(getter_AddRefs(scriptGlobalObject));
|
1999-11-23 03:02:01 +00:00
|
|
|
|
2000-02-04 07:27:30 +00:00
|
|
|
// |xpos| and |ypos| hold the x and y positions of where the popup will be moved to,
|
|
|
|
// in _twips_, in the coordinate system of the _parent view_.
|
|
|
|
PRInt32 xpos = 0, ypos = 0;
|
|
|
|
|
2000-03-02 04:08:04 +00:00
|
|
|
// if we are anchored to our parent, there are certain things we don't want to do
|
|
|
|
// when repositioning the view to fit on the screen, such as end up positioned over
|
|
|
|
// the parent. When doing this reposition, we want to move the popup to the side with
|
|
|
|
// the most room. The combination of anchor and alignment dictate if we readjst
|
|
|
|
// above/below or to the left/right.
|
|
|
|
PRBool anchoredToParent = PR_FALSE;
|
|
|
|
PRBool readjustAboveBelow = PR_FALSE;
|
|
|
|
|
|
|
|
if ( aXPos != -1 || aYPos != -1 ) {
|
2000-02-08 09:30:15 +00:00
|
|
|
|
|
|
|
// for this case, we've been handed a specific x/y location (in client coordinates) for
|
|
|
|
// the popup. However, we may be deeply nested in a frameset, etc and so the client coordinates
|
|
|
|
// need some adjusting.
|
|
|
|
nsCOMPtr<nsIDOMXULDocument> xulDoc ( do_QueryInterface(document) );
|
|
|
|
PRInt32 newXPos = 0, newYPos = 0;
|
|
|
|
AdjustClientXYForNestedDocuments ( xulDoc, presShell, aXPos, aYPos, &newXPos, &newYPos );
|
|
|
|
|
|
|
|
xpos = NSIntPixelsToTwips(newXPos, p2t);
|
|
|
|
ypos = NSIntPixelsToTwips(newYPos, p2t);
|
1999-12-08 11:30:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2000-03-02 04:08:04 +00:00
|
|
|
anchoredToParent = PR_TRUE;
|
|
|
|
|
1999-11-23 03:02:01 +00:00
|
|
|
xpos = parentPos.x + offset.x;
|
|
|
|
ypos = parentPos.y + offset.y;
|
2000-03-02 04:08:04 +00:00
|
|
|
|
|
|
|
// move the popup according to the anchor/alignment attributes. This will also tell us
|
|
|
|
// which axis the popup is flush against in case we have to move it around later.
|
|
|
|
AdjustPositionForAnchorAlign ( &xpos, &ypos, parentRect, aPopupAnchor, aPopupAlign, &readjustAboveBelow );
|
1999-09-10 08:47:12 +00:00
|
|
|
}
|
1999-12-08 11:30:47 +00:00
|
|
|
|
2000-04-21 06:55:13 +00:00
|
|
|
// Compute info about the screen dimensions. Because of multiple monitor systems,
|
|
|
|
// the left or top sides of the screen may be in negative space (main monitor is on the
|
|
|
|
// right, etc). We need to be sure to do the right thing.
|
1999-11-23 03:02:01 +00:00
|
|
|
nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(scriptGlobalObject));
|
|
|
|
nsCOMPtr<nsIDOMScreen> screen;
|
|
|
|
window->GetScreen(getter_AddRefs(screen));
|
2000-04-21 06:55:13 +00:00
|
|
|
PRInt32 screenWidth = 0, screenHeight = 0;
|
|
|
|
PRInt32 screenLeft = 0, screenTop = 0;
|
|
|
|
PRInt32 screenRight = 0, screenBottom = 0;
|
2000-03-23 21:10:09 +00:00
|
|
|
if ( mMenuCanOverlapOSBar ) {
|
2000-04-21 06:55:13 +00:00
|
|
|
screen->GetLeft(&screenLeft);
|
|
|
|
screen->GetTop(&screenTop);
|
2000-03-23 21:10:09 +00:00
|
|
|
screen->GetWidth(&screenWidth);
|
|
|
|
screen->GetHeight(&screenHeight);
|
|
|
|
}
|
|
|
|
else {
|
2000-04-21 06:55:13 +00:00
|
|
|
screen->GetAvailLeft(&screenLeft);
|
|
|
|
screen->GetAvailTop(&screenTop);
|
2000-03-23 21:10:09 +00:00
|
|
|
screen->GetAvailWidth(&screenWidth);
|
|
|
|
screen->GetAvailHeight(&screenHeight);
|
|
|
|
}
|
2000-03-16 05:13:15 +00:00
|
|
|
screenRight = screenLeft + screenWidth;
|
|
|
|
screenBottom = screenTop + screenHeight;
|
|
|
|
|
|
|
|
// inset the screen by 5px so that menus don't butt up against the side
|
|
|
|
const PRInt32 kTrimMargin = 5;
|
|
|
|
screenLeft += kTrimMargin;
|
|
|
|
screenTop += kTrimMargin;
|
|
|
|
screenRight -= kTrimMargin;
|
|
|
|
screenBottom -= kTrimMargin;
|
|
|
|
screenWidth -= 2 * kTrimMargin;
|
|
|
|
screenHeight -= 2 * kTrimMargin;
|
|
|
|
|
2000-03-02 04:08:04 +00:00
|
|
|
PRInt32 screenTopTwips = NSIntPixelsToTwips(screenTop, p2t);
|
|
|
|
PRInt32 screenLeftTwips = NSIntPixelsToTwips(screenLeft, p2t);
|
2000-02-04 07:27:30 +00:00
|
|
|
PRInt32 screenWidthTwips = NSIntPixelsToTwips(screenWidth, p2t);
|
|
|
|
PRInt32 screenHeightTwips = NSIntPixelsToTwips(screenHeight, p2t);
|
|
|
|
PRInt32 screenRightTwips = NSIntPixelsToTwips(screenRight, p2t);
|
|
|
|
PRInt32 screenBottomTwips = NSIntPixelsToTwips(screenBottom, p2t);
|
1999-11-23 03:02:01 +00:00
|
|
|
|
2000-02-04 07:27:30 +00:00
|
|
|
// Recall that |xpos| and |ypos| are in the coordinate system of the parent view. In
|
|
|
|
// order to determine the screen coordinates of where our view will end up, we
|
|
|
|
// need to find the x/y position of the parent view in screen coords. That is done
|
|
|
|
// by getting the widget associated with the parent view and determining the offset
|
|
|
|
// based on converting (0,0) in its coordinate space to screen coords. We then
|
2000-03-02 04:08:04 +00:00
|
|
|
// offset that point by (|xpos|,|ypos|) to get the true screen coordinates of
|
2000-02-04 07:27:30 +00:00
|
|
|
// the view. *whew*
|
|
|
|
nsCOMPtr<nsIWidget> parentViewWidget;
|
2000-02-04 07:44:43 +00:00
|
|
|
GetWidgetForView ( parentView, *getter_AddRefs(parentViewWidget) );
|
2000-03-02 04:08:04 +00:00
|
|
|
nsRect localParentWidgetRect(0,0,0,0), screenParentWidgetRect;
|
|
|
|
parentViewWidget->WidgetToScreen ( localParentWidgetRect, screenParentWidgetRect );
|
|
|
|
PRInt32 screenViewLocX = NSIntPixelsToTwips(screenParentWidgetRect.x,p2t) + (xpos - parentPos.x);
|
|
|
|
PRInt32 screenViewLocY = NSIntPixelsToTwips(screenParentWidgetRect.y,p2t) + (ypos - parentPos.y);
|
|
|
|
|
|
|
|
if ( anchoredToParent ) {
|
|
|
|
|
|
|
|
//
|
|
|
|
// Popup is anchored to the parent, guarantee that it does not cover the parent. We
|
|
|
|
// shouldn't do anything funky if it will already fit on the screen as is.
|
|
|
|
//
|
|
|
|
|
|
|
|
// compute screen coordinates of parent frame so we can play with it. Make sure we put it
|
|
|
|
// into twips as everything else is as well.
|
|
|
|
nsRect screenParentFrameRect ( NSTwipsToIntPixels(offset.x,t2p), NSTwipsToIntPixels(offset.y,t2p),
|
|
|
|
parentRect.width, parentRect.height );
|
|
|
|
parentViewWidget->WidgetToScreen ( screenParentFrameRect, screenParentFrameRect );
|
|
|
|
screenParentFrameRect.x = NSIntPixelsToTwips(screenParentFrameRect.x, p2t);
|
|
|
|
screenParentFrameRect.y = NSIntPixelsToTwips(screenParentFrameRect.y, p2t);
|
|
|
|
|
|
|
|
// if it doesn't fit on the screen, do our magic.
|
|
|
|
if ( (screenViewLocX + mRect.width) > screenRightTwips ||
|
|
|
|
(screenViewLocY + mRect.height) > screenBottomTwips ) {
|
|
|
|
|
|
|
|
// figure out which side of the parent has the most free space so we can move/resize
|
|
|
|
// the popup there. This should still work if the parent frame is partially screen.
|
|
|
|
PRBool switchSides = IsMoreRoomOnOtherSideOfParent ( readjustAboveBelow, screenViewLocX, screenViewLocY,
|
|
|
|
screenParentFrameRect, screenTopTwips, screenLeftTwips,
|
|
|
|
screenBottomTwips, screenRightTwips );
|
|
|
|
|
|
|
|
// move the popup to the correct side, if necessary. Note that MovePopupToOtherSideOfParent()
|
|
|
|
// can change width/height of |mRect|.
|
|
|
|
if ( switchSides )
|
|
|
|
MovePopupToOtherSideOfParent ( readjustAboveBelow, &xpos, &ypos, &screenViewLocX, &screenViewLocY,
|
|
|
|
screenParentFrameRect, screenTopTwips, screenLeftTwips,
|
|
|
|
screenBottomTwips, screenRightTwips );
|
|
|
|
|
|
|
|
// We are allowed to move the popup along the axis to which we're not anchored to the parent
|
|
|
|
// in order to get it to not spill off the screen.
|
|
|
|
if ( readjustAboveBelow ) {
|
2000-03-16 05:13:15 +00:00
|
|
|
// move left to be on screen, but don't let it go off the screen at the left
|
2000-03-02 04:08:04 +00:00
|
|
|
if ( (screenViewLocX + mRect.width) > screenRightTwips ) {
|
|
|
|
PRInt32 moveDistX = (screenViewLocX + mRect.width) - screenRightTwips;
|
2000-03-16 05:13:15 +00:00
|
|
|
if ( screenViewLocX - moveDistX < screenLeftTwips )
|
|
|
|
moveDistX = screenViewLocX - screenLeftTwips;
|
2000-03-02 04:08:04 +00:00
|
|
|
screenViewLocX -= moveDistX;
|
|
|
|
xpos -= moveDistX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2000-03-16 05:13:15 +00:00
|
|
|
// move it up to be on screen, but don't let it go off the screen at the top
|
2000-03-02 04:08:04 +00:00
|
|
|
if ( (screenViewLocY + mRect.height) > screenBottomTwips ) {
|
|
|
|
PRInt32 moveDistY = (screenViewLocY + mRect.height) - screenBottomTwips;
|
2000-03-16 05:13:15 +00:00
|
|
|
if ( screenViewLocY - moveDistY < screenTopTwips )
|
|
|
|
moveDistY = screenViewLocY - screenTopTwips;
|
2000-03-02 04:08:04 +00:00
|
|
|
screenViewLocY -= moveDistY;
|
|
|
|
ypos -= moveDistY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resize it to fit on the screen. By this point, we've given the popup as much
|
|
|
|
// room as we can w/out covering the parent. If it still can't be as big
|
|
|
|
// as it wants to be, well, it just has to suck up and deal.
|
|
|
|
PRInt32 xSpillage = (screenViewLocX + mRect.width) - screenRightTwips;
|
|
|
|
if ( xSpillage > 0 )
|
|
|
|
mRect.width -= xSpillage;
|
|
|
|
PRInt32 ySpillage = (screenViewLocY + mRect.height) - screenBottomTwips;
|
|
|
|
if ( ySpillage > 0 )
|
|
|
|
mRect.height -= ySpillage;
|
|
|
|
|
|
|
|
} // if it doesn't fit on screen
|
|
|
|
} // if anchored to parent
|
|
|
|
else {
|
|
|
|
|
|
|
|
//
|
|
|
|
// Popup not anchored to anything, just make sure it's on the screen by any
|
|
|
|
// means necessary
|
|
|
|
//
|
|
|
|
|
|
|
|
// add back in the parentPos offset. Not sure why, but we need this for mail/news
|
|
|
|
// context menus and we can't do this in the case where there popup is anchored.
|
|
|
|
screenViewLocX += parentPos.x;
|
|
|
|
screenViewLocY += parentPos.y;
|
|
|
|
|
|
|
|
// shrink to fit onto the screen, vertically and horizontally
|
|
|
|
if(mRect.width > screenWidthTwips)
|
|
|
|
mRect.width = screenWidthTwips;
|
|
|
|
if(mRect.height > screenHeightTwips)
|
|
|
|
mRect.height = screenHeightTwips;
|
|
|
|
|
|
|
|
// we now know where the view is...make sure that it's still onscreen at all!
|
|
|
|
if ( screenViewLocX < screenLeftTwips ) {
|
|
|
|
PRInt32 moveDistX = screenLeftTwips - screenViewLocX;
|
|
|
|
xpos += moveDistX;
|
|
|
|
screenViewLocX += moveDistX;
|
|
|
|
}
|
|
|
|
if ( screenViewLocY < screenTopTwips ) {
|
|
|
|
PRInt32 moveDistY = screenTopTwips - screenViewLocY;
|
|
|
|
ypos += moveDistY;
|
|
|
|
screenViewLocY += moveDistY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure it is not even partially offscreen.
|
|
|
|
if ( (screenViewLocX + mRect.width) > screenRightTwips ) {
|
|
|
|
// as a result of moving the popup, it might end up under the mouse. This
|
|
|
|
// would be bad as the subsequent mouse_up would trigger whatever
|
|
|
|
// unsuspecting item happens to be at that position. To get around this, make
|
|
|
|
// move it so the right edge is where the mouse is, as we're guaranteed
|
|
|
|
// that the mouse is on the screen!
|
|
|
|
xpos -= mRect.width;
|
|
|
|
}
|
|
|
|
if ( (screenViewLocY + mRect.height) > screenBottomTwips )
|
|
|
|
ypos -= (screenViewLocY + mRect.height) - screenBottomTwips;
|
|
|
|
|
|
|
|
}
|
2000-02-04 07:27:30 +00:00
|
|
|
|
|
|
|
// finally move and resize it
|
|
|
|
viewManager->MoveViewTo(view, xpos, ypos);
|
|
|
|
viewManager->ResizeView(view, mRect.width, mRect.height);
|
1999-11-23 03:02:01 +00:00
|
|
|
|
2000-03-03 01:50:43 +00:00
|
|
|
nsAutoString shouldDisplay, menuActive;
|
|
|
|
mContent->GetAttribute(kNameSpaceID_None, nsXULAtoms::menuactive, menuActive);
|
2000-04-16 11:19:26 +00:00
|
|
|
if (!menuActive.EqualsWithConversion("true")) {
|
2000-03-03 01:50:43 +00:00
|
|
|
mContent->GetAttribute(kNameSpaceID_None, nsXULAtoms::menutobedisplayed, shouldDisplay);
|
2000-04-16 11:19:26 +00:00
|
|
|
if ( shouldDisplay.EqualsWithConversion("true") )
|
|
|
|
mContent->SetAttribute(kNameSpaceID_None, nsXULAtoms::menuactive, NS_ConvertASCIItoUCS2("true"), PR_TRUE);
|
2000-03-03 01:50:43 +00:00
|
|
|
}
|
2000-02-15 17:14:59 +00:00
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-09-21 01:03:00 +00:00
|
|
|
nsMenuPopupFrame::GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
|
1999-07-21 07:42:16 +00:00
|
|
|
{
|
2000-04-04 06:43:02 +00:00
|
|
|
nsIFrame* immediateParent = nsnull;
|
|
|
|
GetInsertionPoint(&immediateParent);
|
|
|
|
if (!immediateParent)
|
|
|
|
immediateParent = this;
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
nsIFrame* currFrame = nsnull;
|
|
|
|
nsIFrame* startFrame = nsnull;
|
1999-07-22 09:01:55 +00:00
|
|
|
if (aStart) {
|
1999-09-21 01:03:00 +00:00
|
|
|
aStart->QueryInterface(kIFrameIID, (void**)&currFrame);
|
|
|
|
if (currFrame) {
|
|
|
|
startFrame = currFrame;
|
1999-07-22 09:01:55 +00:00
|
|
|
currFrame->GetNextSibling(&currFrame);
|
1999-09-21 01:03:00 +00:00
|
|
|
}
|
1999-07-22 09:01:55 +00:00
|
|
|
}
|
2000-04-04 06:43:02 +00:00
|
|
|
else
|
|
|
|
immediateParent->FirstChild(mPresContext,
|
|
|
|
nsnull,
|
|
|
|
&currFrame);
|
|
|
|
|
1999-07-22 09:01:55 +00:00
|
|
|
|
1999-07-22 01:59:09 +00:00
|
|
|
while (currFrame) {
|
1999-07-21 07:42:16 +00:00
|
|
|
nsCOMPtr<nsIContent> current;
|
1999-07-22 01:59:09 +00:00
|
|
|
currFrame->GetContent(getter_AddRefs(current));
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
// See if it's a menu item.
|
1999-07-26 01:35:39 +00:00
|
|
|
if (IsValidItem(current)) {
|
1999-09-21 01:03:00 +00:00
|
|
|
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
|
|
|
|
*aResult = menuFrame.get();
|
|
|
|
NS_IF_ADDREF(*aResult);
|
1999-07-21 07:42:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-07-22 01:59:09 +00:00
|
|
|
currFrame->GetNextSibling(&currFrame);
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
|
|
|
|
2000-04-04 06:43:02 +00:00
|
|
|
immediateParent->FirstChild(mPresContext,
|
|
|
|
nsnull,
|
|
|
|
&currFrame);
|
1999-07-22 01:59:09 +00:00
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
// Still don't have anything. Try cycling from the beginning.
|
1999-09-21 01:03:00 +00:00
|
|
|
while (currFrame && currFrame != startFrame) {
|
1999-07-21 07:42:16 +00:00
|
|
|
nsCOMPtr<nsIContent> current;
|
1999-07-22 01:59:09 +00:00
|
|
|
currFrame->GetContent(getter_AddRefs(current));
|
1999-07-21 07:42:16 +00:00
|
|
|
|
|
|
|
// See if it's a menu item.
|
1999-07-26 01:35:39 +00:00
|
|
|
if (IsValidItem(current)) {
|
1999-09-21 01:03:00 +00:00
|
|
|
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
|
|
|
|
*aResult = menuFrame.get();
|
|
|
|
NS_IF_ADDREF(*aResult);
|
1999-07-21 07:42:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-07-22 01:59:09 +00:00
|
|
|
|
|
|
|
currFrame->GetNextSibling(&currFrame);
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// No luck. Just return our start value.
|
|
|
|
*aResult = aStart;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-09-21 01:03:00 +00:00
|
|
|
nsMenuPopupFrame::GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
|
1999-07-21 07:42:16 +00:00
|
|
|
{
|
2000-04-04 06:43:02 +00:00
|
|
|
nsIFrame* immediateParent = nsnull;
|
|
|
|
GetInsertionPoint(&immediateParent);
|
|
|
|
if (!immediateParent)
|
|
|
|
immediateParent = this;
|
|
|
|
|
|
|
|
nsIFrame* first;
|
|
|
|
immediateParent->FirstChild(mPresContext,
|
|
|
|
nsnull, &first);
|
|
|
|
nsFrameList frames(first);
|
|
|
|
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
nsIFrame* currFrame = nsnull;
|
|
|
|
nsIFrame* startFrame = nsnull;
|
1999-07-22 09:01:55 +00:00
|
|
|
if (aStart) {
|
1999-09-21 01:03:00 +00:00
|
|
|
aStart->QueryInterface(kIFrameIID, (void**)&currFrame);
|
|
|
|
if (currFrame) {
|
|
|
|
startFrame = currFrame;
|
2000-04-04 06:43:02 +00:00
|
|
|
currFrame = frames.GetPrevSiblingFor(currFrame);
|
1999-09-21 01:03:00 +00:00
|
|
|
}
|
1999-07-22 09:01:55 +00:00
|
|
|
}
|
2000-04-04 06:43:02 +00:00
|
|
|
else currFrame = frames.LastChild();
|
1999-07-22 09:01:55 +00:00
|
|
|
|
1999-07-22 01:59:09 +00:00
|
|
|
while (currFrame) {
|
1999-07-21 07:42:16 +00:00
|
|
|
nsCOMPtr<nsIContent> current;
|
1999-07-22 01:59:09 +00:00
|
|
|
currFrame->GetContent(getter_AddRefs(current));
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
// See if it's a menu item.
|
1999-07-26 01:35:39 +00:00
|
|
|
if (IsValidItem(current)) {
|
1999-09-21 01:03:00 +00:00
|
|
|
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
|
|
|
|
*aResult = menuFrame.get();
|
|
|
|
NS_IF_ADDREF(*aResult);
|
1999-07-21 07:42:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-04-04 06:43:02 +00:00
|
|
|
currFrame = frames.GetPrevSiblingFor(currFrame);
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
|
|
|
|
2000-04-04 06:43:02 +00:00
|
|
|
currFrame = frames.LastChild();
|
1999-07-22 01:59:09 +00:00
|
|
|
|
|
|
|
// Still don't have anything. Try cycling from the end.
|
1999-09-21 01:03:00 +00:00
|
|
|
while (currFrame && currFrame != startFrame) {
|
1999-07-21 07:42:16 +00:00
|
|
|
nsCOMPtr<nsIContent> current;
|
1999-07-22 01:59:09 +00:00
|
|
|
currFrame->GetContent(getter_AddRefs(current));
|
1999-07-21 07:42:16 +00:00
|
|
|
|
|
|
|
// See if it's a menu item.
|
1999-07-26 01:35:39 +00:00
|
|
|
if (IsValidItem(current)) {
|
1999-09-21 01:03:00 +00:00
|
|
|
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
|
|
|
|
*aResult = menuFrame.get();
|
|
|
|
NS_IF_ADDREF(*aResult);
|
1999-07-21 07:42:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-07-22 01:59:09 +00:00
|
|
|
|
2000-04-04 06:43:02 +00:00
|
|
|
currFrame = frames.GetPrevSiblingFor(currFrame);
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// No luck. Just return our start value.
|
|
|
|
*aResult = aStart;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-02-13 08:33:39 +00:00
|
|
|
NS_IMETHODIMP nsMenuPopupFrame::GetCurrentMenuItem(nsIMenuFrame** aResult)
|
|
|
|
{
|
|
|
|
*aResult = mCurrentMenu;
|
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
|
1999-07-21 07:42:16 +00:00
|
|
|
{
|
|
|
|
if (mCurrentMenu == aMenuItem)
|
|
|
|
return NS_OK;
|
1999-09-21 01:03:00 +00:00
|
|
|
|
1999-07-22 09:01:55 +00:00
|
|
|
// Unset the current child.
|
1999-07-21 08:51:41 +00:00
|
|
|
if (mCurrentMenu) {
|
1999-09-21 01:03:00 +00:00
|
|
|
PRBool isOpen = PR_FALSE;
|
|
|
|
mCurrentMenu->MenuIsOpen(isOpen);
|
1999-09-25 03:39:35 +00:00
|
|
|
mCurrentMenu->SelectMenu(PR_FALSE);
|
2000-02-13 08:33:39 +00:00
|
|
|
if (isOpen) {
|
|
|
|
// Don't close up immediately.
|
|
|
|
// Kick off a close timer.
|
2000-02-13 08:44:31 +00:00
|
|
|
KillCloseTimer(); // Ensure we don't have another stray waiting closure.
|
2000-02-13 08:33:39 +00:00
|
|
|
PRInt32 menuDelay = 300; // ms
|
|
|
|
|
|
|
|
nsILookAndFeel * lookAndFeel;
|
|
|
|
if (NS_OK == nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull,
|
|
|
|
kILookAndFeelIID, (void**)&lookAndFeel)) {
|
|
|
|
lookAndFeel->GetMetric(nsILookAndFeel::eMetric_SubmenuDelay, menuDelay);
|
|
|
|
NS_RELEASE(lookAndFeel);
|
|
|
|
}
|
1999-09-25 03:39:35 +00:00
|
|
|
|
2000-02-13 08:33:39 +00:00
|
|
|
// Kick off the timer.
|
|
|
|
NS_NewTimer(getter_AddRefs(mCloseTimer));
|
|
|
|
mCloseTimer->Init(this, menuDelay, NS_PRIORITY_HIGHEST);
|
|
|
|
mTimerMenu = mCurrentMenu;
|
|
|
|
}
|
1999-07-21 08:51:41 +00:00
|
|
|
}
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
// Set the new child.
|
1999-07-21 08:51:41 +00:00
|
|
|
if (aMenuItem) {
|
1999-09-21 01:03:00 +00:00
|
|
|
aMenuItem->SelectMenu(PR_TRUE);
|
1999-07-21 08:51:41 +00:00
|
|
|
}
|
1999-07-22 09:01:55 +00:00
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
mCurrentMenu = aMenuItem;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-07-21 08:51:41 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-10-26 04:44:41 +00:00
|
|
|
nsMenuPopupFrame::CaptureMouseEvents(nsIPresContext* aPresContext, PRBool aGrabMouseEvents)
|
1999-07-21 08:51:41 +00:00
|
|
|
{
|
|
|
|
// get its view
|
|
|
|
nsIView* view = nsnull;
|
1999-10-26 04:44:41 +00:00
|
|
|
GetView(aPresContext, &view);
|
1999-07-21 08:51:41 +00:00
|
|
|
nsCOMPtr<nsIViewManager> viewMan;
|
|
|
|
PRBool result;
|
|
|
|
|
1999-09-10 08:47:12 +00:00
|
|
|
nsCOMPtr<nsIWidget> widget;
|
|
|
|
|
1999-07-21 08:51:41 +00:00
|
|
|
if (view) {
|
|
|
|
view->GetViewManager(*getter_AddRefs(viewMan));
|
|
|
|
if (viewMan) {
|
1999-09-10 08:47:12 +00:00
|
|
|
view->GetWidget(*getter_AddRefs(widget));
|
1999-07-21 08:51:41 +00:00
|
|
|
if (aGrabMouseEvents) {
|
|
|
|
viewMan->GrabMouseEvents(view,result);
|
|
|
|
mIsCapturingMouseEvents = PR_TRUE;
|
1999-09-21 01:03:00 +00:00
|
|
|
//widget->CaptureMouse(PR_TRUE);
|
1999-07-21 08:51:41 +00:00
|
|
|
} else {
|
|
|
|
viewMan->GrabMouseEvents(nsnull,result);
|
|
|
|
mIsCapturingMouseEvents = PR_FALSE;
|
1999-09-21 01:03:00 +00:00
|
|
|
//widget->CaptureMouse(PR_FALSE);
|
1999-07-21 08:51:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-02-09 09:34:35 +00:00
|
|
|
NS_IMETHODIMP
|
1999-07-23 08:36:39 +00:00
|
|
|
nsMenuPopupFrame::Escape(PRBool& aHandledFlag)
|
1999-07-23 07:49:43 +00:00
|
|
|
{
|
1999-07-23 08:36:39 +00:00
|
|
|
if (!mCurrentMenu)
|
2000-02-09 09:34:35 +00:00
|
|
|
return NS_OK;
|
1999-07-23 07:49:43 +00:00
|
|
|
|
1999-07-23 08:36:39 +00:00
|
|
|
// See if our menu is open.
|
1999-09-21 01:03:00 +00:00
|
|
|
PRBool isOpen = PR_FALSE;
|
|
|
|
mCurrentMenu->MenuIsOpen(isOpen);
|
|
|
|
if (isOpen) {
|
1999-07-23 08:36:39 +00:00
|
|
|
// Let the child menu handle this.
|
1999-09-21 01:03:00 +00:00
|
|
|
mCurrentMenu->Escape(aHandledFlag);
|
1999-07-23 08:36:39 +00:00
|
|
|
if (!aHandledFlag) {
|
|
|
|
// We should close up.
|
1999-09-21 01:03:00 +00:00
|
|
|
mCurrentMenu->OpenMenu(PR_FALSE);
|
1999-07-23 08:36:39 +00:00
|
|
|
aHandledFlag = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
2000-02-09 09:34:35 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
1999-07-23 07:49:43 +00:00
|
|
|
}
|
|
|
|
|
2000-02-09 09:34:35 +00:00
|
|
|
NS_IMETHODIMP
|
1999-07-24 22:02:23 +00:00
|
|
|
nsMenuPopupFrame::Enter()
|
|
|
|
{
|
|
|
|
// Give it to the child.
|
1999-09-21 01:03:00 +00:00
|
|
|
if (mCurrentMenu)
|
|
|
|
mCurrentMenu->Enter();
|
2000-02-09 09:34:35 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
1999-07-24 22:02:23 +00:00
|
|
|
}
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
nsIMenuFrame*
|
1999-07-23 07:49:43 +00:00
|
|
|
nsMenuPopupFrame::FindMenuWithShortcut(PRUint32 aLetter)
|
|
|
|
{
|
2000-04-04 06:43:02 +00:00
|
|
|
|
1999-07-23 07:49:43 +00:00
|
|
|
// Enumerate over our list of frames.
|
2000-04-04 06:43:02 +00:00
|
|
|
nsIFrame* immediateParent = nsnull;
|
|
|
|
GetInsertionPoint(&immediateParent);
|
|
|
|
if (!immediateParent)
|
|
|
|
immediateParent = this;
|
|
|
|
|
|
|
|
nsIFrame* currFrame;
|
|
|
|
immediateParent->FirstChild(mPresContext, nsnull, &currFrame);
|
|
|
|
|
1999-07-23 07:49:43 +00:00
|
|
|
while (currFrame) {
|
|
|
|
nsCOMPtr<nsIContent> current;
|
|
|
|
currFrame->GetContent(getter_AddRefs(current));
|
|
|
|
|
|
|
|
// See if it's a menu item.
|
1999-07-26 01:35:39 +00:00
|
|
|
if (IsValidItem(current)) {
|
1999-07-23 07:49:43 +00:00
|
|
|
// Get the shortcut attribute.
|
2000-04-16 11:19:26 +00:00
|
|
|
nsAutoString shortcutKey;
|
1999-07-26 01:19:49 +00:00
|
|
|
current->GetAttribute(kNameSpaceID_None, nsXULAtoms::accesskey, shortcutKey);
|
1999-07-23 07:49:43 +00:00
|
|
|
if (shortcutKey.Length() > 0) {
|
|
|
|
// We've got something.
|
2000-02-09 09:34:35 +00:00
|
|
|
char tempChar[2];
|
|
|
|
tempChar[0] = aLetter;
|
|
|
|
tempChar[1] = 0;
|
2000-04-16 11:19:26 +00:00
|
|
|
nsAutoString tempChar2; tempChar2.AssignWithConversion(tempChar);
|
2000-02-09 09:34:35 +00:00
|
|
|
|
|
|
|
if (shortcutKey.EqualsIgnoreCase(tempChar2)) {
|
1999-07-23 07:49:43 +00:00
|
|
|
// We match!
|
1999-09-21 01:03:00 +00:00
|
|
|
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
|
|
|
|
if (menuFrame)
|
|
|
|
return menuFrame.get();
|
|
|
|
return nsnull;
|
1999-07-23 07:49:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currFrame->GetNextSibling(&currFrame);
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2000-02-09 09:34:35 +00:00
|
|
|
NS_IMETHODIMP
|
1999-07-23 05:47:43 +00:00
|
|
|
nsMenuPopupFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
|
|
|
{
|
1999-07-23 07:56:27 +00:00
|
|
|
if (mCurrentMenu) {
|
1999-09-21 01:03:00 +00:00
|
|
|
PRBool isOpen = PR_FALSE;
|
|
|
|
mCurrentMenu->MenuIsOpen(isOpen);
|
|
|
|
if (isOpen) {
|
1999-07-23 07:56:27 +00:00
|
|
|
// No way this applies to us. Give it to our child.
|
1999-09-21 01:03:00 +00:00
|
|
|
mCurrentMenu->ShortcutNavigation(aLetter, aHandledFlag);
|
2000-02-09 09:34:35 +00:00
|
|
|
return NS_OK;
|
1999-07-23 07:56:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This applies to us. Let's see if one of the shortcuts applies
|
1999-09-21 01:03:00 +00:00
|
|
|
nsIMenuFrame* result = FindMenuWithShortcut(aLetter);
|
1999-07-23 07:56:27 +00:00
|
|
|
if (result) {
|
|
|
|
// We got one!
|
|
|
|
aHandledFlag = PR_TRUE;
|
|
|
|
SetCurrentMenuItem(result);
|
2000-01-12 08:16:32 +00:00
|
|
|
result->Enter();
|
1999-07-23 07:56:27 +00:00
|
|
|
}
|
2000-02-09 09:34:35 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
1999-07-23 05:47:43 +00:00
|
|
|
}
|
|
|
|
|
2000-02-09 09:34:35 +00:00
|
|
|
NS_IMETHODIMP
|
1999-07-22 09:01:55 +00:00
|
|
|
nsMenuPopupFrame::KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag)
|
|
|
|
{
|
|
|
|
// This method only gets called if we're open.
|
1999-07-26 06:29:48 +00:00
|
|
|
if (!mCurrentMenu && (aDirection == NS_VK_RIGHT || aDirection == NS_VK_LEFT)) {
|
1999-07-22 09:01:55 +00:00
|
|
|
// We've been opened, but we haven't had anything selected.
|
1999-07-26 06:29:48 +00:00
|
|
|
// We can handle RIGHT, but our parent handles LEFT.
|
|
|
|
if (aDirection == NS_VK_RIGHT) {
|
1999-09-21 01:03:00 +00:00
|
|
|
nsIMenuFrame* nextItem;
|
1999-07-26 06:29:48 +00:00
|
|
|
GetNextMenuItem(nsnull, &nextItem);
|
|
|
|
if (nextItem) {
|
|
|
|
aHandledFlag = PR_TRUE;
|
|
|
|
SetCurrentMenuItem(nextItem);
|
|
|
|
}
|
|
|
|
}
|
2000-02-09 09:34:35 +00:00
|
|
|
return NS_OK;
|
1999-07-22 09:01:55 +00:00
|
|
|
}
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
PRBool isContainer = PR_FALSE;
|
|
|
|
PRBool isOpen = PR_FALSE;
|
|
|
|
if (mCurrentMenu) {
|
|
|
|
mCurrentMenu->MenuIsContainer(isContainer);
|
|
|
|
mCurrentMenu->MenuIsOpen(isOpen);
|
|
|
|
|
|
|
|
if (isOpen) {
|
1999-07-25 00:16:11 +00:00
|
|
|
// Give our child a shot.
|
1999-09-21 01:03:00 +00:00
|
|
|
mCurrentMenu->KeyboardNavigation(aDirection, aHandledFlag);
|
1999-07-25 00:16:11 +00:00
|
|
|
}
|
1999-09-21 01:03:00 +00:00
|
|
|
else if (aDirection == NS_VK_RIGHT && isContainer) {
|
1999-07-25 00:16:11 +00:00
|
|
|
// The menu is not yet open. Open it and select the first item.
|
|
|
|
aHandledFlag = PR_TRUE;
|
1999-09-21 01:03:00 +00:00
|
|
|
mCurrentMenu->OpenMenu(PR_TRUE);
|
|
|
|
mCurrentMenu->SelectFirstItem();
|
1999-07-25 00:16:11 +00:00
|
|
|
}
|
1999-07-22 09:01:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aHandledFlag)
|
2000-02-09 09:34:35 +00:00
|
|
|
return NS_OK; // The child menu took it for us.
|
1999-07-22 09:01:55 +00:00
|
|
|
|
|
|
|
// For the vertical direction, we can move up or down.
|
|
|
|
if (aDirection == NS_VK_UP || aDirection == NS_VK_DOWN) {
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
nsIMenuFrame* nextItem;
|
1999-07-22 09:01:55 +00:00
|
|
|
|
|
|
|
if (aDirection == NS_VK_DOWN)
|
|
|
|
GetNextMenuItem(mCurrentMenu, &nextItem);
|
|
|
|
else GetPreviousMenuItem(mCurrentMenu, &nextItem);
|
|
|
|
|
|
|
|
SetCurrentMenuItem(nextItem);
|
|
|
|
|
|
|
|
aHandledFlag = PR_TRUE;
|
|
|
|
}
|
1999-09-21 01:03:00 +00:00
|
|
|
else if (mCurrentMenu && isContainer && isOpen) {
|
1999-07-26 04:38:28 +00:00
|
|
|
if (aDirection == NS_VK_LEFT) {
|
|
|
|
// Close it up.
|
1999-09-21 01:03:00 +00:00
|
|
|
mCurrentMenu->OpenMenu(PR_FALSE);
|
1999-07-26 06:29:48 +00:00
|
|
|
aHandledFlag = PR_TRUE;
|
1999-07-26 04:38:28 +00:00
|
|
|
}
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
2000-02-09 09:34:35 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
1999-07-24 01:59:32 +00:00
|
|
|
}
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::GetParentPopup(nsIMenuParent** aMenuParent)
|
|
|
|
{
|
|
|
|
*aMenuParent = nsnull;
|
|
|
|
nsIFrame* frame;
|
|
|
|
GetParent(&frame);
|
|
|
|
if (frame) {
|
|
|
|
nsIFrame* grandparent;
|
|
|
|
frame->GetParent(&grandparent);
|
|
|
|
if (grandparent) {
|
|
|
|
nsCOMPtr<nsIMenuParent> menuParent = do_QueryInterface(grandparent);
|
|
|
|
if (menuParent) {
|
|
|
|
*aMenuParent = menuParent.get();
|
|
|
|
NS_ADDREF(*aMenuParent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-12 20:45:47 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::HideChain()
|
|
|
|
{
|
1999-10-05 23:31:06 +00:00
|
|
|
// Stop capturing rollups
|
|
|
|
// (must do this during Hide, which happens before the menu item is executed,
|
|
|
|
// since this reinstates normal event handling.)
|
|
|
|
if (nsMenuFrame::mDismissalListener)
|
|
|
|
nsMenuFrame::mDismissalListener->Unregister();
|
|
|
|
|
1999-08-12 20:45:47 +00:00
|
|
|
nsIFrame* frame;
|
|
|
|
GetParent(&frame);
|
|
|
|
if (frame) {
|
1999-09-21 01:03:00 +00:00
|
|
|
nsCOMPtr<nsIPopupSetFrame> popupSetFrame = do_QueryInterface(frame);
|
|
|
|
if (popupSetFrame) {
|
|
|
|
// Destroy the popup.
|
|
|
|
popupSetFrame->HidePopup();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(frame);
|
|
|
|
if (!menuFrame)
|
|
|
|
return NS_OK;
|
|
|
|
|
1999-08-12 20:45:47 +00:00
|
|
|
menuFrame->ActivateMenu(PR_FALSE);
|
|
|
|
menuFrame->SelectMenu(PR_FALSE);
|
|
|
|
|
|
|
|
// Get the parent.
|
|
|
|
nsCOMPtr<nsIMenuParent> menuParent;
|
|
|
|
menuFrame->GetMenuParent(getter_AddRefs(menuParent));
|
|
|
|
if (menuParent)
|
|
|
|
menuParent->HideChain();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-07-24 01:59:32 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::DismissChain()
|
|
|
|
{
|
1999-09-25 03:39:35 +00:00
|
|
|
// Stop capturing rollups
|
|
|
|
if (nsMenuFrame::mDismissalListener)
|
|
|
|
nsMenuFrame::mDismissalListener->Unregister();
|
|
|
|
|
1999-07-24 01:59:32 +00:00
|
|
|
// Get our menu parent.
|
|
|
|
nsIFrame* frame;
|
|
|
|
GetParent(&frame);
|
|
|
|
if (frame) {
|
1999-09-21 01:03:00 +00:00
|
|
|
nsCOMPtr<nsIPopupSetFrame> popupSetFrame = do_QueryInterface(frame);
|
|
|
|
if (popupSetFrame) {
|
|
|
|
// Destroy the popup.
|
|
|
|
popupSetFrame->DestroyPopup();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(frame);
|
|
|
|
if (!menuFrame)
|
|
|
|
return NS_OK;
|
|
|
|
|
1999-07-24 01:59:32 +00:00
|
|
|
menuFrame->OpenMenu(PR_FALSE);
|
|
|
|
|
|
|
|
// Get the parent.
|
|
|
|
nsCOMPtr<nsIMenuParent> menuParent;
|
|
|
|
menuFrame->GetMenuParent(getter_AddRefs(menuParent));
|
|
|
|
if (menuParent)
|
|
|
|
menuParent->DismissChain();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-07-26 01:35:39 +00:00
|
|
|
|
1999-09-25 03:39:35 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::GetWidget(nsIWidget **aWidget)
|
|
|
|
{
|
|
|
|
// Get parent view
|
|
|
|
nsIView * view = nsnull;
|
1999-10-26 04:44:41 +00:00
|
|
|
nsMenuPopupFrame::GetNearestEnclosingView(mPresContext, this, &view);
|
1999-09-25 03:39:35 +00:00
|
|
|
if (!view)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
view->GetWidget(*aWidget);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-09-21 01:03:00 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::CreateDismissalListener()
|
|
|
|
{
|
1999-10-04 02:27:09 +00:00
|
|
|
nsMenuDismissalListener *listener = new nsMenuDismissalListener();
|
|
|
|
if (!listener) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsMenuFrame::mDismissalListener = listener;
|
|
|
|
NS_ADDREF(listener);
|
1999-09-21 01:03:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-02-09 09:34:35 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::InstallKeyboardNavigator()
|
|
|
|
{
|
2000-02-18 10:22:20 +00:00
|
|
|
if (mKeyboardNavigator)
|
|
|
|
return NS_OK;
|
|
|
|
|
2000-02-09 09:34:35 +00:00
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
mContent->GetDocument(*getter_AddRefs(doc));
|
|
|
|
nsCOMPtr<nsIDOMEventReceiver> target = do_QueryInterface(doc);
|
|
|
|
|
|
|
|
mTarget = target;
|
|
|
|
mKeyboardNavigator = new nsMenuListener(this);
|
|
|
|
NS_IF_ADDREF(mKeyboardNavigator);
|
|
|
|
|
2000-04-16 11:19:26 +00:00
|
|
|
target->AddEventListener(NS_ConvertASCIItoUCS2("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
|
|
|
target->AddEventListener(NS_ConvertASCIItoUCS2("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
|
|
|
target->AddEventListener(NS_ConvertASCIItoUCS2("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
2000-02-09 09:34:35 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::RemoveKeyboardNavigator()
|
|
|
|
{
|
2000-02-18 10:22:20 +00:00
|
|
|
if (!mKeyboardNavigator)
|
|
|
|
return NS_OK;
|
|
|
|
|
2000-04-16 11:19:26 +00:00
|
|
|
mTarget->RemoveEventListener(NS_ConvertASCIItoUCS2("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
|
|
|
mTarget->RemoveEventListener(NS_ConvertASCIItoUCS2("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
|
|
|
mTarget->RemoveEventListener(NS_ConvertASCIItoUCS2("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
2000-02-09 09:34:35 +00:00
|
|
|
|
|
|
|
NS_IF_RELEASE(mKeyboardNavigator);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// helpers /////////////////////////////////////////////////////////////
|
|
|
|
|
1999-07-26 01:35:39 +00:00
|
|
|
PRBool
|
|
|
|
nsMenuPopupFrame::IsValidItem(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
aContent->GetTag(*getter_AddRefs(tag));
|
1999-07-31 11:29:03 +00:00
|
|
|
if (tag && (tag.get() == nsXULAtoms::menu ||
|
2000-03-13 10:37:57 +00:00
|
|
|
tag.get() == nsXULAtoms::menuitem))
|
1999-07-26 01:35:39 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsMenuPopupFrame::IsDisabled(nsIContent* aContent)
|
|
|
|
{
|
2000-04-16 11:19:26 +00:00
|
|
|
nsString disabled;
|
1999-07-26 01:35:39 +00:00
|
|
|
aContent->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::disabled, disabled);
|
2000-04-16 11:19:26 +00:00
|
|
|
if (disabled.EqualsWithConversion("true"))
|
1999-07-26 01:35:39 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-09-10 08:47:12 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsMenuPopupFrame::HandleEvent(nsIPresContext* aPresContext,
|
1999-09-10 08:47:12 +00:00
|
|
|
nsGUIEvent* aEvent,
|
1999-11-24 06:03:41 +00:00
|
|
|
nsEventStatus* aEventStatus)
|
1999-09-10 08:47:12 +00:00
|
|
|
{
|
1999-09-21 01:03:00 +00:00
|
|
|
return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
1999-09-10 08:47:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsMenuPopupFrame::Destroy(nsIPresContext* aPresContext)
|
1999-09-10 08:47:12 +00:00
|
|
|
{
|
1999-09-21 01:03:00 +00:00
|
|
|
//nsCOMPtr<nsIDOMEventReceiver> target = do_QueryInterface(mContent);
|
|
|
|
//target->RemoveEventListener("mousemove", mMenuPopupEntryListener, PR_TRUE);
|
|
|
|
return nsBoxFrame::Destroy(aPresContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-10-26 04:44:41 +00:00
|
|
|
nsMenuPopupFrame::GetFrameForPoint(nsIPresContext* aPresContext,
|
|
|
|
const nsPoint& aPoint,
|
2000-03-31 07:02:06 +00:00
|
|
|
nsFramePaintLayer aWhichLayer,
|
1999-10-26 04:44:41 +00:00
|
|
|
nsIFrame** aFrame)
|
1999-09-21 01:03:00 +00:00
|
|
|
{
|
2000-03-22 02:43:08 +00:00
|
|
|
return nsBoxFrame::GetFrameForPoint(aPresContext, aPoint, aWhichLayer, aFrame);
|
1999-09-10 08:47:12 +00:00
|
|
|
}
|
2000-02-13 08:33:39 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP_(void)
|
|
|
|
nsMenuPopupFrame::Notify(nsITimer* aTimer)
|
|
|
|
{
|
|
|
|
// Our timer has fired.
|
|
|
|
if (aTimer == mCloseTimer.get()) {
|
|
|
|
PRBool menuOpen = PR_FALSE;
|
|
|
|
mTimerMenu->MenuIsOpen(menuOpen);
|
|
|
|
if (menuOpen) {
|
|
|
|
if (mCurrentMenu != mTimerMenu) {
|
2000-05-12 02:58:21 +00:00
|
|
|
#if 1
|
2000-02-13 08:33:39 +00:00
|
|
|
// See if our child has a current menu.
|
|
|
|
// If so, then we need to be selected.
|
|
|
|
nsIFrame* child;
|
|
|
|
mTimerMenu->GetMenuChild(&child);
|
|
|
|
if (child) {
|
|
|
|
nsCOMPtr<nsIMenuParent> menuPopup = do_QueryInterface(child);
|
|
|
|
nsCOMPtr<nsIMenuFrame> frame;
|
|
|
|
menuPopup->GetCurrentMenuItem(getter_AddRefs(frame));
|
|
|
|
if (frame) {
|
|
|
|
SetCurrentMenuItem(mTimerMenu);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Close up.
|
|
|
|
mTimerMenu->OpenMenu(PR_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Close up.
|
|
|
|
mTimerMenu->OpenMenu(PR_FALSE);
|
|
|
|
}
|
2000-05-12 02:58:21 +00:00
|
|
|
#else
|
|
|
|
// this isn't current anymore -- close up.
|
|
|
|
mTimerMenu->OpenMenu(PR_FALSE);
|
|
|
|
#endif
|
2000-02-13 08:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mCloseTimer->Cancel();
|
|
|
|
mCloseTimer = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
mCloseTimer = nsnull;
|
|
|
|
mTimerMenu = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuPopupFrame::KillCloseTimer()
|
|
|
|
{
|
|
|
|
if (mCloseTimer && mTimerMenu) {
|
|
|
|
PRBool menuOpen = PR_FALSE;
|
|
|
|
mTimerMenu->MenuIsOpen(menuOpen);
|
|
|
|
if (menuOpen) {
|
|
|
|
mTimerMenu->OpenMenu(PR_FALSE);
|
|
|
|
}
|
|
|
|
mCloseTimer->Cancel();
|
|
|
|
mCloseTimer = nsnull;
|
|
|
|
mTimerMenu = nsnull;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|