1999-07-18 06:36:37 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
|
|
|
|
1999-07-20 08:19:47 +00:00
|
|
|
#include "nsXULAtoms.h"
|
1999-07-26 01:35:39 +00:00
|
|
|
#include "nsHTMLAtoms.h"
|
1999-07-18 06:36:37 +00:00
|
|
|
#include "nsMenuFrame.h"
|
1999-07-21 02:56:23 +00:00
|
|
|
#include "nsBoxFrame.h"
|
1999-07-18 06:36:37 +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-18 06:41:41 +00:00
|
|
|
#include "nsLayoutAtoms.h"
|
1999-07-20 09:35:35 +00:00
|
|
|
#include "nsMenuPopupFrame.h"
|
1999-07-21 07:42:16 +00:00
|
|
|
#include "nsMenuBarFrame.h"
|
1999-07-26 02:26:26 +00:00
|
|
|
#include "nsIView.h"
|
|
|
|
#include "nsIWidget.h"
|
1999-07-18 06:36:37 +00:00
|
|
|
|
1999-07-18 06:48:03 +00:00
|
|
|
#define NS_MENU_POPUP_LIST_INDEX (NS_AREA_FRAME_ABSOLUTE_LIST_INDEX + 1)
|
|
|
|
|
1999-07-26 06:29:48 +00:00
|
|
|
static gEatMouseMove = PR_FALSE;
|
|
|
|
|
1999-07-18 06:36:37 +00:00
|
|
|
//
|
|
|
|
// NS_NewMenuFrame
|
|
|
|
//
|
|
|
|
// Wrapper for creating a new menu popup container
|
|
|
|
//
|
|
|
|
nsresult
|
1999-07-23 05:17:08 +00:00
|
|
|
NS_NewMenuFrame(nsIFrame** aNewFrame, PRUint32 aFlags)
|
1999-07-18 06:36:37 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
|
|
if (nsnull == aNewFrame) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
nsMenuFrame* it = new nsMenuFrame;
|
|
|
|
if ( !it )
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
*aNewFrame = it;
|
1999-07-23 05:10:57 +00:00
|
|
|
if (aFlags)
|
|
|
|
it->SetIsMenu(PR_TRUE);
|
1999-07-18 06:36:37 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
NS_IMETHODIMP_(nsrefcnt)
|
|
|
|
nsMenuFrame::AddRef(void)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(nsrefcnt)
|
|
|
|
nsMenuFrame::Release(void)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsMenuFrame::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
|
|
{
|
|
|
|
if (NULL == aInstancePtr) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
*aInstancePtr = NULL;
|
1999-07-25 01:14:43 +00:00
|
|
|
if (aIID.Equals(nsITimerCallback::GetIID())) {
|
|
|
|
*aInstancePtr = (void*)(nsITimerCallback*) this;
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-07-21 07:42:16 +00:00
|
|
|
return nsBoxFrame::QueryInterface(aIID, aInstancePtr);
|
|
|
|
}
|
1999-07-18 06:36:37 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// nsMenuFrame cntr
|
|
|
|
//
|
|
|
|
nsMenuFrame::nsMenuFrame()
|
1999-07-25 00:16:11 +00:00
|
|
|
:mMenuOpen(PR_FALSE), mIsMenu(PR_FALSE), mMenuParent(nsnull)
|
1999-07-18 06:36:37 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
} // cntr
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::Init(nsIPresContext& aPresContext,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aContext,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
|
|
|
nsresult rv = nsBoxFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
|
|
|
|
|
|
|
|
// Set our menu parent.
|
|
|
|
nsCOMPtr<nsIMenuParent> menuparent = do_QueryInterface(aParent);
|
|
|
|
mMenuParent = menuparent.get();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1999-07-18 06:44:03 +00:00
|
|
|
// The following methods are all overridden to ensure that the xpmenuchildren frame
|
|
|
|
// is placed in the appropriate list.
|
1999-07-18 06:41:41 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::FirstChild(nsIAtom* aListName,
|
|
|
|
nsIFrame** aFirstChild) const
|
|
|
|
{
|
|
|
|
if (nsLayoutAtoms::popupList == aListName) {
|
|
|
|
*aFirstChild = mPopupFrames.FirstChild();
|
|
|
|
} else {
|
1999-07-21 02:56:23 +00:00
|
|
|
nsBoxFrame::FirstChild(aListName, aFirstChild);
|
1999-07-18 06:41:41 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-07-18 06:44:03 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::SetInitialChildList(nsIPresContext& aPresContext,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aChildList)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (nsLayoutAtoms::popupList == aListName) {
|
|
|
|
mPopupFrames.SetFrames(aChildList);
|
|
|
|
} else {
|
1999-07-20 08:19:47 +00:00
|
|
|
|
|
|
|
nsFrameList frames(aChildList);
|
|
|
|
|
|
|
|
// We may have an xpmenuchildren in here. Get it out, and move it into
|
|
|
|
// the popup frame list.
|
|
|
|
nsIFrame* frame = frames.FirstChild();
|
|
|
|
while (frame) {
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
frame->GetContent(getter_AddRefs(content));
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
content->GetTag(*getter_AddRefs(tag));
|
|
|
|
if (tag.get() == nsXULAtoms::xpmenuchildren) {
|
|
|
|
// Remove this frame from the list and place it in the other list.
|
|
|
|
frames.RemoveFrame(frame);
|
|
|
|
mPopupFrames.AppendFrame(this, frame);
|
1999-07-21 02:56:23 +00:00
|
|
|
rv = nsBoxFrame::SetInitialChildList(aPresContext, aListName, aChildList);
|
1999-07-20 08:19:47 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
}
|
1999-07-21 02:56:23 +00:00
|
|
|
rv = nsBoxFrame::SetInitialChildList(aPresContext, aListName, aChildList);
|
1999-07-18 06:44:03 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
1999-07-18 06:48:03 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::GetAdditionalChildListName(PRInt32 aIndex,
|
|
|
|
nsIAtom** aListName) const
|
|
|
|
{
|
|
|
|
// Maintain a separate child list for the menu contents.
|
|
|
|
// This is necessary because we don't want the menu contents to be included in the layout
|
|
|
|
// of the menu's single item because it would take up space, when it is supposed to
|
|
|
|
// be floating above the display.
|
1999-07-20 09:35:35 +00:00
|
|
|
/*NS_PRECONDITION(nsnull != aListName, "null OUT parameter pointer");
|
1999-07-18 06:48:03 +00:00
|
|
|
|
|
|
|
*aListName = nsnull;
|
|
|
|
if (NS_MENU_POPUP_LIST_INDEX == aIndex) {
|
|
|
|
*aListName = nsLayoutAtoms::popupList;
|
|
|
|
NS_ADDREF(*aListName);
|
|
|
|
return NS_OK;
|
1999-07-20 09:35:35 +00:00
|
|
|
}*/
|
1999-07-21 02:56:23 +00:00
|
|
|
return nsBoxFrame::GetAdditionalChildListName(aIndex, aListName);
|
1999-07-18 06:48:03 +00:00
|
|
|
}
|
1999-07-18 06:52:06 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-07-22 02:24:52 +00:00
|
|
|
nsMenuFrame::Destroy(nsIPresContext& aPresContext)
|
1999-07-18 06:52:06 +00:00
|
|
|
{
|
|
|
|
// Cleanup frames in popup child list
|
1999-07-22 04:00:57 +00:00
|
|
|
mPopupFrames.DestroyFrames(aPresContext);
|
1999-07-22 02:24:52 +00:00
|
|
|
return nsBoxFrame::Destroy(aPresContext);
|
1999-07-18 06:52:06 +00:00
|
|
|
}
|
1999-07-19 09:36:24 +00:00
|
|
|
|
|
|
|
// Called to prevent events from going to anything inside the menu.
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::GetFrameForPoint(const nsPoint& aPoint,
|
|
|
|
nsIFrame** aFrame)
|
|
|
|
{
|
|
|
|
*aFrame = this; // Capture all events so that we can perform selection
|
|
|
|
return NS_OK;
|
1999-07-20 08:19:47 +00:00
|
|
|
}
|
1999-07-20 09:35:35 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::HandleEvent(nsIPresContext& aPresContext,
|
|
|
|
nsGUIEvent* aEvent,
|
|
|
|
nsEventStatus& aEventStatus)
|
|
|
|
{
|
|
|
|
aEventStatus = nsEventStatus_eConsumeDoDefault;
|
1999-07-26 01:35:39 +00:00
|
|
|
|
|
|
|
if (IsDisabled()) // Disabled menus process no events.
|
|
|
|
return NS_OK;
|
|
|
|
|
1999-07-20 09:50:48 +00:00
|
|
|
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) {
|
1999-07-25 00:16:11 +00:00
|
|
|
PRBool isMenuBar = PR_TRUE;
|
|
|
|
if (mMenuParent)
|
|
|
|
mMenuParent->IsMenuBar(isMenuBar);
|
|
|
|
|
|
|
|
if (isMenuBar) {
|
|
|
|
// The menu item was selected. Bring up the menu.
|
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
if (frame) {
|
|
|
|
// We have children.
|
|
|
|
ToggleMenuState();
|
|
|
|
if (!IsOpen()) {
|
|
|
|
// We closed up. The menu bar should always be
|
|
|
|
// deactivated when this happens.
|
|
|
|
mMenuParent->SetActive(PR_FALSE);
|
|
|
|
}
|
1999-07-23 08:36:39 +00:00
|
|
|
}
|
1999-07-20 09:35:35 +00:00
|
|
|
}
|
|
|
|
}
|
1999-07-25 00:16:11 +00:00
|
|
|
else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP && !IsMenu() &&
|
|
|
|
mMenuParent) {
|
1999-07-24 01:59:32 +00:00
|
|
|
// The menu item was invoked and can now be dismissed.
|
1999-07-24 22:02:23 +00:00
|
|
|
// XXX Execute the execute event handler.
|
1999-07-25 00:16:11 +00:00
|
|
|
mMenuParent->DismissChain();
|
1999-07-24 01:59:32 +00:00
|
|
|
}
|
1999-07-21 07:42:16 +00:00
|
|
|
else if (aEvent->message == NS_MOUSE_EXIT) {
|
1999-07-25 00:16:11 +00:00
|
|
|
// Kill our timer if one is active.
|
|
|
|
if (mOpenTimer) {
|
|
|
|
mOpenTimer->Cancel();
|
|
|
|
mOpenTimer = nsnull;
|
|
|
|
}
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
// Deactivate the menu.
|
1999-07-23 08:36:39 +00:00
|
|
|
PRBool isActive = PR_FALSE;
|
|
|
|
PRBool isMenuBar = PR_FALSE;
|
|
|
|
if (mMenuParent) {
|
|
|
|
mMenuParent->IsMenuBar(isMenuBar);
|
1999-07-26 01:58:51 +00:00
|
|
|
PRBool cancel = PR_TRUE;
|
1999-07-23 08:36:39 +00:00
|
|
|
if (isMenuBar) {
|
|
|
|
mMenuParent->GetIsActive(isActive);
|
1999-07-26 01:58:51 +00:00
|
|
|
if (isActive) cancel = PR_FALSE;
|
1999-07-23 08:36:39 +00:00
|
|
|
}
|
1999-07-26 01:58:51 +00:00
|
|
|
|
1999-07-26 04:38:28 +00:00
|
|
|
if (cancel) {
|
|
|
|
if (IsMenu() && !isMenuBar && mMenuOpen) {
|
|
|
|
// Submenus don't get closed up.
|
|
|
|
}
|
|
|
|
else mMenuParent->SetCurrentMenuItem(nsnull);
|
|
|
|
}
|
1999-07-23 08:36:39 +00:00
|
|
|
}
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
1999-07-25 01:14:43 +00:00
|
|
|
else if (aEvent->message == NS_MOUSE_MOVE && mMenuParent) {
|
1999-07-26 06:29:48 +00:00
|
|
|
if (gEatMouseMove) {
|
|
|
|
gEatMouseMove = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
// Let the menu parent know we're the new item.
|
1999-07-25 01:14:43 +00:00
|
|
|
mMenuParent->SetCurrentMenuItem(this);
|
|
|
|
|
|
|
|
PRBool isMenuBar = PR_TRUE;
|
|
|
|
mMenuParent->IsMenuBar(isMenuBar);
|
1999-07-25 00:16:11 +00:00
|
|
|
|
|
|
|
// If we're a menu (and not a menu item),
|
|
|
|
// kick off the timer.
|
1999-07-25 01:14:43 +00:00
|
|
|
if (!isMenuBar && IsMenu() && !mMenuOpen && !mOpenTimer) {
|
|
|
|
// We're a menu, we're closed, and no timer has been kicked off.
|
|
|
|
NS_NewTimer(getter_AddRefs(mOpenTimer));
|
|
|
|
mOpenTimer->Init(this, 250); // 250 ms delay
|
|
|
|
}
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
1999-07-20 09:35:35 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::ToggleMenuState()
|
1999-07-21 07:42:16 +00:00
|
|
|
{
|
1999-07-20 09:35:35 +00:00
|
|
|
if (mMenuOpen) {
|
1999-07-21 07:42:16 +00:00
|
|
|
OpenMenu(PR_FALSE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
OpenMenu(PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::SelectMenu(PRBool aActivateFlag)
|
|
|
|
{
|
|
|
|
if (aActivateFlag) {
|
|
|
|
// Highlight the menu.
|
|
|
|
mContent->SetAttribute(kNameSpaceID_None, nsXULAtoms::menuactive, "true", PR_TRUE);
|
1999-07-20 09:35:35 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-07-21 07:42:16 +00:00
|
|
|
// Unhighlight the menu.
|
|
|
|
mContent->UnsetAttribute(kNameSpaceID_None, nsXULAtoms::menuactive, PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::OpenMenu(PRBool aActivateFlag)
|
|
|
|
{
|
1999-07-26 06:29:48 +00:00
|
|
|
gEatMouseMove = PR_TRUE;
|
|
|
|
|
1999-07-23 05:10:57 +00:00
|
|
|
if (!mIsMenu)
|
|
|
|
return;
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
nsCOMPtr<nsIContent> child;
|
|
|
|
GetMenuChildrenElement(getter_AddRefs(child));
|
|
|
|
|
1999-07-21 08:51:41 +00:00
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
|
|
|
|
|
1999-07-21 07:42:16 +00:00
|
|
|
if (aActivateFlag) {
|
1999-07-24 22:02:23 +00:00
|
|
|
// XXX Execute the oncreate handler
|
1999-07-22 09:49:35 +00:00
|
|
|
// Sync up the view.
|
1999-07-24 22:51:50 +00:00
|
|
|
PRBool onMenuBar = PR_TRUE;
|
|
|
|
if (mMenuParent)
|
|
|
|
mMenuParent->IsMenuBar(onMenuBar);
|
|
|
|
|
1999-07-22 09:49:35 +00:00
|
|
|
if (menuPopup)
|
1999-07-24 22:51:50 +00:00
|
|
|
menuPopup->SyncViewWithFrame(onMenuBar);
|
1999-07-22 09:49:35 +00:00
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
// Open the menu.
|
1999-07-21 07:42:16 +00:00
|
|
|
mContent->SetAttribute(kNameSpaceID_None, nsXULAtoms::open, "true", PR_TRUE);
|
1999-07-22 09:01:55 +00:00
|
|
|
if (child) {
|
|
|
|
// We've got some children for real.
|
1999-07-21 07:42:16 +00:00
|
|
|
child->SetAttribute(kNameSpaceID_None, nsXULAtoms::menuactive, "true", PR_TRUE);
|
1999-07-22 09:01:55 +00:00
|
|
|
|
|
|
|
// Tell the menu bar we're active.
|
1999-07-23 08:36:39 +00:00
|
|
|
mMenuParent->SetActive(PR_TRUE);
|
1999-07-22 09:01:55 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
mMenuOpen = PR_TRUE;
|
1999-07-21 08:51:41 +00:00
|
|
|
//if (menuPopup)
|
|
|
|
// menuPopup->CaptureMouseEvents(PR_TRUE);
|
1999-07-20 09:35:35 +00:00
|
|
|
}
|
1999-07-21 07:42:16 +00:00
|
|
|
else {
|
1999-07-24 22:02:23 +00:00
|
|
|
// Close the menu.
|
|
|
|
// XXX Execute the ondestroy handler
|
1999-07-21 07:42:16 +00:00
|
|
|
mContent->UnsetAttribute(kNameSpaceID_None, nsXULAtoms::open, PR_TRUE);
|
|
|
|
if (child)
|
|
|
|
child->UnsetAttribute(kNameSpaceID_None, nsXULAtoms::menuactive, PR_TRUE);
|
|
|
|
mMenuOpen = PR_FALSE;
|
1999-07-22 09:49:35 +00:00
|
|
|
|
|
|
|
// Make sure we clear out our own items.
|
|
|
|
if (menuPopup)
|
|
|
|
menuPopup->SetCurrentMenuItem(nsnull);
|
1999-07-26 02:26:26 +00:00
|
|
|
|
|
|
|
// Set the focus back to our view's widget.
|
|
|
|
nsIView* view;
|
|
|
|
GetView(&view);
|
|
|
|
if (!view) {
|
|
|
|
nsPoint offset;
|
|
|
|
GetOffsetFromView(offset, &view);
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIWidget> widget;
|
|
|
|
view->GetWidget(*getter_AddRefs(widget));
|
|
|
|
widget->SetFocus();
|
1999-07-21 07:42:16 +00:00
|
|
|
}
|
1999-07-20 09:35:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::GetMenuChildrenElement(nsIContent** aResult)
|
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
if (frame) {
|
|
|
|
frame->GetContent(aResult);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMenuFrame::Reflow(nsIPresContext& aPresContext,
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
nsReflowStatus& aStatus)
|
|
|
|
{
|
1999-07-21 02:56:23 +00:00
|
|
|
nsresult rv = nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
|
1999-07-20 09:35:35 +00:00
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
|
1999-07-21 09:45:21 +00:00
|
|
|
if (!frame || (rv != NS_OK))
|
|
|
|
return rv;
|
1999-07-20 10:35:24 +00:00
|
|
|
|
1999-07-21 09:45:21 +00:00
|
|
|
// Constrain the child's width and height to aAvailableWidth and aAvailableHeight
|
|
|
|
nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
|
|
|
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame,
|
|
|
|
availSize);
|
|
|
|
kidReflowState.mComputedWidth = NS_UNCONSTRAINEDSIZE;
|
|
|
|
kidReflowState.mComputedHeight = NS_UNCONSTRAINEDSIZE;
|
|
|
|
|
|
|
|
// Reflow child
|
|
|
|
nscoord w = aDesiredSize.width;
|
|
|
|
nscoord h = aDesiredSize.height;
|
1999-07-23 01:02:09 +00:00
|
|
|
|
1999-07-21 09:45:21 +00:00
|
|
|
rv = ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, aStatus);
|
|
|
|
|
|
|
|
// Set the child's width and height to its desired size
|
|
|
|
nsRect rect;
|
|
|
|
frame->GetRect(rect);
|
|
|
|
rect.width = aDesiredSize.width;
|
|
|
|
rect.height = aDesiredSize.height;
|
|
|
|
frame->SetRect(rect);
|
|
|
|
|
|
|
|
// Don't let it affect our size.
|
|
|
|
aDesiredSize.width = w;
|
|
|
|
aDesiredSize.height = h;
|
1999-07-23 01:02:09 +00:00
|
|
|
|
1999-07-20 09:35:35 +00:00
|
|
|
return rv;
|
1999-07-20 10:13:43 +00:00
|
|
|
}
|
1999-07-22 09:01:55 +00:00
|
|
|
|
1999-07-23 05:47:43 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
|
|
|
{
|
1999-07-23 07:39:16 +00:00
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
if (frame) {
|
|
|
|
nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
|
|
|
|
popup->ShortcutNavigation(aLetter, aHandledFlag);
|
|
|
|
}
|
1999-07-23 05:47:43 +00:00
|
|
|
}
|
|
|
|
|
1999-07-22 09:01:55 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag)
|
|
|
|
{
|
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
if (frame) {
|
|
|
|
nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
|
|
|
|
popup->KeyboardNavigation(aDirection, aHandledFlag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-23 07:49:43 +00:00
|
|
|
void
|
1999-07-23 08:36:39 +00:00
|
|
|
nsMenuFrame::Escape(PRBool& aHandledFlag)
|
1999-07-23 07:49:43 +00:00
|
|
|
{
|
1999-07-23 08:36:39 +00:00
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
if (frame) {
|
|
|
|
nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
|
|
|
|
popup->Escape(aHandledFlag);
|
|
|
|
}
|
1999-07-23 07:49:43 +00:00
|
|
|
}
|
|
|
|
|
1999-07-24 22:02:23 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::Enter()
|
|
|
|
{
|
|
|
|
if (!mMenuOpen) {
|
|
|
|
// The enter key press applies to us.
|
|
|
|
// XXX Execute the event handler.
|
1999-07-25 00:16:11 +00:00
|
|
|
if (!IsMenu() && mMenuParent) {
|
1999-07-24 22:02:23 +00:00
|
|
|
// Close up the parent.
|
|
|
|
mMenuParent->DismissChain();
|
|
|
|
}
|
1999-07-25 00:16:11 +00:00
|
|
|
else {
|
1999-07-24 22:02:23 +00:00
|
|
|
OpenMenu(PR_TRUE);
|
|
|
|
SelectFirstItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
if (frame) {
|
|
|
|
nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
|
|
|
|
popup->Enter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-22 09:01:55 +00:00
|
|
|
void
|
|
|
|
nsMenuFrame::SelectFirstItem()
|
|
|
|
{
|
1999-07-23 09:34:14 +00:00
|
|
|
nsIFrame* frame = mPopupFrames.FirstChild();
|
|
|
|
if (frame) {
|
|
|
|
nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
|
|
|
|
nsIFrame* result;
|
|
|
|
popup->GetNextMenuItem(nsnull, &result);
|
|
|
|
popup->SetCurrentMenuItem(result);
|
|
|
|
}
|
1999-07-25 00:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsMenuFrame::IsMenu()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
mContent->GetTag(*getter_AddRefs(tag));
|
|
|
|
if (tag.get() == nsXULAtoms::xpmenu)
|
|
|
|
return PR_TRUE;
|
|
|
|
return PR_FALSE;
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsMenuFrame::Notify(nsITimer* aTimer)
|
|
|
|
{
|
|
|
|
// Our timer has fired.
|
1999-07-26 04:38:28 +00:00
|
|
|
if (aTimer == mOpenTimer.get()) {
|
|
|
|
if (!mMenuOpen && mMenuParent) {
|
|
|
|
nsAutoString active = "";
|
|
|
|
mContent->GetAttribute(kNameSpaceID_None, nsXULAtoms::menuactive, active);
|
|
|
|
if (active == "true") {
|
|
|
|
// We're still the active menu.
|
|
|
|
OpenMenu(PR_TRUE);
|
|
|
|
}
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
1999-07-26 04:38:28 +00:00
|
|
|
mOpenTimer->Cancel();
|
|
|
|
mOpenTimer = nsnull;
|
1999-07-25 01:14:43 +00:00
|
|
|
}
|
1999-07-26 04:38:28 +00:00
|
|
|
|
1999-07-25 01:14:43 +00:00
|
|
|
mOpenTimer = nsnull;
|
|
|
|
}
|
1999-07-26 01:35:39 +00:00
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsMenuFrame::IsDisabled()
|
|
|
|
{
|
|
|
|
nsString disabled = "";
|
|
|
|
mContent->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::disabled, disabled);
|
|
|
|
if (disabled == "true")
|
|
|
|
return PR_TRUE;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|