Mozilla/mozilla/widget/src/mac/nsDynamicMDEF.cpp
dmose%mozilla.org 92d791b7b0 updated license boilerplate to xPL 1.1, a=chofmann@netscape.com,r=endico@mozilla.org
git-svn-id: svn://10.0.0.236/trunk@52908 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-06 03:40:37 +00:00

566 lines
17 KiB
C++

/* -*- 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.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/
*
* 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.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsDynamicMDEF.h"
#include "nsCOMPtr.h"
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsMenuBar.h"
#include "nsIMenuBar.h"
#include <Resources.h>
#include <MixedMode.h>
#include <A4Stuff.h>
extern nsIMenuBar * gMacMenubar;
extern Handle gSystemMDEFHandle;
#pragma options align=mac68k
RoutineDescriptorPtr gOriginaldesc;
RoutineDescriptorPtr gmdefUPP;
// Caching the Mac menu
nsVoidArray gPreviousMenuHandleStack;
nsVoidArray gPreviousMenuStack;
nsIMenuBar * gCachedMacMenubar;
MenuHandle gSizedMenu = nsnull;
extern Handle gMDEF;
bool gTested = false;
MenuHandle gCachedMenuHandle = nsnull;
PRUint16 gCachedMenuID = 0;
extern PRInt16 gMenuDepth; // volital running total
extern PRInt16 gCurrentMenuDepth; // The menu depth that is currently shown
extern MenuHandle gLevel2HierMenu;
extern MenuHandle gLevel3HierMenu;
extern MenuHandle gLevel4HierMenu;
extern MenuHandle gLevel5HierMenu;
PRUint32 gCurrentMenuItem = 0; // 1 based ala MacOS
PRUint32 gCurrentTopLevelMenuIndex = 0;
MenuHandle gPreviousTopLevelMenuHandle = nsnull;
nsIMenu * gPreviousTopLevelMenu = nsnull;
nsIMenu * gPreviousMenu = nsnull;
MenuHandle gPreviousMenuHandle = nsnull;
//------------------------------------------------------------------------------
// Internal functions
void nsDynamicChooseItem(
MenuHandle theMenu,
Rect * menuRect,
Point hitPt,
short * whichItem);
void nsDynamicSizeTheMenu(
MenuHandle theMenu);
void nsBuildMenu(
MenuHandle theMenu,
PRBool isChild);
void nsPushMenu(
nsIMenu * aMenu);
void nsPopMenu(
nsIMenu ** aMenu);
void nsPushMenuHandle(
MenuHandle aMenu);
void nsPopMenuHandle(
MenuHandle * aMenu);
void nsCallSystemMDEF(
short message,
MenuHandle theMenu,
Rect * menuRect,
Point hitPt,
short * whichItem);
void nsDoMagic(
MenuHandle theMenu);
void nsPostBuild(
nsIMenu * menu,
MenuHandle theMenu,
PRBool isChild);
bool nsIsHierChild(
MenuHandle theMenu);
void nsCheckDestroy(
MenuHandle theMenu,
short * whichItem);
//void TestPreviousMenuStackUnwind(nsIMenu * aMenuJustBuilt, MenuHandle aMenuHandleJustBuilt);
//void TestCheckDestroy(MenuHandle theMenu, short * whichItem);
//void TestPostBuild(nsIMenu * menu, MenuHandle theMenu, PRBool isChild);
//------------------------------------------------------------------------------
pascal void nsDynamicMDEFMain(
short message,
MenuHandle theMenu,
Rect * menuRect,
Point hitPt,
short * whichItem)
{
switch (message) {
case kMenuDrawMsg:
//printf(" Draw passed in menu is = %d \n", *theMenu);
//printf(" t= %d l= %d b= %d r= %d\n", (*menuRect).top, (*menuRect).left, (*menuRect).bottom, (*menuRect).right);
//printf(" Point.v = %d Point.h = %d\n", hitPt.v, hitPt.h);
//printf(" whichItem = %d \n", *whichItem);
//printf(" theMenu.menuID = %d \n", (**theMenu).menuID);
nsCheckDestroy(theMenu, whichItem);
break;
case kMenuChooseMsg:
// Keep track of currently chosen item
nsDynamicChooseItem(theMenu, menuRect, hitPt, whichItem);
return; // Yes, intentional return as CallSystemMDEF has happened already
break;
case kMenuSizeMsg:
//printf("Size passed in menu is = %d \n", *theMenu);
//printf(" t= %d l= %d b= %d r= %d \n", (*menuRect).top, (*menuRect).left, (*menuRect).bottom ,(*menuRect).right);
//printf(" Point.v = %d Point.h = %d \n", hitPt.v, hitPt.h);
//printf(" whichItem = %d \n", *whichItem);
//printf(" theMenu.menuID = %d \n", (**theMenu).menuID);
nsCheckDestroy(theMenu, whichItem);
// Need to make sure that we rebuild the menu every time...
if (gPreviousMenuHandleStack.Count()) {
nsIMenu * menu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1];
MenuHandle menuHandle = (MenuHandle) gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1];
//printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count());
//printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count());
if( menu && menuHandle ) {
if( menuHandle == theMenu ) {
nsCOMPtr<nsIMenuListener> listener(do_QueryInterface(menu));
if(listener) {
//printf("MenuPop \n");
nsMenuEvent mevent;
mevent.message = NS_MENU_SELECTED;
mevent.eventStructType = NS_MENU_EVENT;
mevent.point.x = 0;
mevent.point.y = 0;
mevent.widget = nsnull;
mevent.time = PR_IntervalNow();
mevent.mCommand = (PRUint32) nsnull;
// UNDO
listener->MenuDeselected(mevent);
gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1);
//printf("%d items now on gPreviousMenuStack \n", gPreviousMenuStack.Count());
gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1);
}
}
}
}
nsDynamicSizeTheMenu(theMenu);
break;
}
nsCallSystemMDEF(message, theMenu, menuRect, hitPt, whichItem);
// Force a size message next time we draw this menu
if(message == kMenuDrawMsg) {
SInt8 state = ::HGetState((Handle)theMenu);
HLock((Handle)theMenu);
(**theMenu).menuWidth = -1;
(**theMenu).menuHeight = -1;
HSetState((Handle)theMenu, state);
}
}
//------------------------------------------------------------------------------
void nsCheckDestroy(MenuHandle theMenu, short * whichItem)
{
// Determine if we have unselected the previous popup. If so we need to
// destroy it now.
bool changeOccured = true;
bool isChild = false;
if(gCurrentMenuItem == *whichItem)
changeOccured = false;
if(!gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1])
changeOccured = false;
if(nsIsHierChild(theMenu))
isChild = true;
if(changeOccured && !isChild) {
nsPreviousMenuStackUnwind(nsnull, theMenu);
if(gCurrentMenuDepth > 1)
gCurrentMenuDepth--;
}
}
//------------------------------------------------------------------------------
void nsDynamicChooseItem(
MenuHandle theMenu,
Rect * menuRect,
Point hitPt,
short * whichItem)
{
//printf("enter DynamicChooseItem \n");
nsCallSystemMDEF(kMenuChooseMsg, theMenu, menuRect, hitPt, whichItem);
nsCheckDestroy(theMenu, whichItem);
gCurrentMenuItem = *whichItem;
//printf("exit DynamicChooseItem \n");
}
//------------------------------------------------------------------------------
void nsDynamicSizeTheMenu(
MenuHandle theMenu)
{
//printf("enter DynamicSizeTheMenu \n");
nsDoMagic(theMenu);
//printf("exit DynamicSizeTheMenu \n");
}
//------------------------------------------------------------------------------
bool nsIsHierChild(MenuHandle theMenu)
{
if(theMenu == gLevel2HierMenu) {
if(gCurrentMenuDepth <= 2) return true;
} else if(theMenu == gLevel3HierMenu) {
if(gCurrentMenuDepth <= 3) return true;
} else if(theMenu == gLevel4HierMenu) {
if(gCurrentMenuDepth <= 4) return true;
} else if(theMenu == gLevel5HierMenu) {
if(gCurrentMenuDepth <= 5) return true;
}
return false;
}
//------------------------------------------------------------------------------
void nsDoMagic(MenuHandle theMenu)
{
//printf("DoMagic \n");
// ask if this is a child of the previous menu
PRBool isChild = PR_FALSE;
if(gPreviousMenuStack[gPreviousMenuStack.Count() - 1]) {
if(nsIsHierChild(theMenu)) {
isChild = PR_TRUE;
}
}
if(theMenu == gLevel2HierMenu) {
gCurrentMenuDepth = 2;
} else if(theMenu == gLevel3HierMenu) {
gCurrentMenuDepth = 3;
} else if(theMenu == gLevel4HierMenu) {
gCurrentMenuDepth = 4;
} else if(theMenu == gLevel5HierMenu) {
gCurrentMenuDepth = 5;
} else {
gCurrentMenuDepth = 1;
}
nsBuildMenu(theMenu, isChild);
}
//------------------------------------------------------------------------------
void nsBuildMenu(MenuHandle theMenu, PRBool isChild)
{
// printf("enter BuildMenu \n");
nsIMenuBar * menubar = gMacMenubar; // Global for current menubar
if(!menubar || !theMenu) {
return;
}
nsMenuEvent mevent;
mevent.message = NS_MENU_SELECTED;
mevent.eventStructType = NS_MENU_EVENT;
mevent.point.x = 0;
mevent.point.y = 0;
mevent.widget = nsnull;
mevent.time = PR_IntervalNow();
mevent.mCommand = (PRUint32) theMenu;
// If toplevel
if( gCurrentMenuDepth < 2 ) {
PRUint32 numMenus = 0;
menubar->GetMenuCount(numMenus);
numMenus--;
for(PRInt32 i = numMenus; i >= 0; i--) {
nsIMenu * menu = nsnull;
menubar->GetMenuAt(i, menu);
if(menu) {
nsCOMPtr<nsIMenuListener> listener(do_QueryInterface(menu));
if(listener) {
// Reset menu depth count
gMenuDepth = 0;
nsEventStatus status = listener->MenuSelected(mevent);
if(status != nsEventStatus_eIgnore) {
nsPostBuild(menu, theMenu, isChild);
gPreviousTopLevelMenuHandle = theMenu;
gPreviousTopLevelMenu = menu;
NS_RELEASE(menu);
//printf("exit BuildMenu \n");
return;
}
}
NS_RELEASE(menu);
}
}
} else {
// Not top level, so we can't use recursive MenuSelect <sigh>
// We must use the previously chosen menu item in combination
// with the current menu to determine what menu needs to be constructed
nsISupports * supports = nsnull;
//printf("gCurrentMenuItem = %d \n", gCurrentMenuItem);
if(gCurrentMenuItem) {
nsIMenu * prevMenu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1];
//printf("gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count() );
if(prevMenu) {
prevMenu->GetItemAt(gCurrentMenuItem - 1, supports);
nsCOMPtr<nsIMenu> menu(do_QueryInterface(supports));
if(menu) {
nsCOMPtr<nsIMenuListener> menulistener(do_QueryInterface(supports));
menulistener->MenuSelected(mevent);
nsPostBuild(menu, theMenu, isChild);
}
}
}
}
//printf("exit BuildMenu \n");
}
//------------------------------------------------------------------------------
void nsPostBuild(nsIMenu * menu, MenuHandle theMenu, PRBool isChild)
{
// it is built now
if(isChild || (gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1] != theMenu)) {
nsPushMenu(menu);
nsPushMenuHandle(theMenu);
//printf("Push: %d items in gMenuHandleStack \n", gMenuHandleStack.Count());
}
}
//------------------------------------------------------------------------------
void nsCallSystemMDEF(
short message,
MenuHandle theMenu,
Rect * menuRect,
Point hitPt,
short * whichItem)
{
SInt8 state = ::HGetState(gSystemMDEFHandle);
::HLock(gSystemMDEFHandle);
gmdefUPP = ::NewRoutineDescriptor( (ProcPtr)*gSystemMDEFHandle, uppMenuDefProcInfo, kM68kISA);
CallMenuDefProc(
gmdefUPP,
message,
theMenu,
menuRect,
hitPt,
whichItem);
::DisposeRoutineDescriptor(gmdefUPP);
::HSetState(gSystemMDEFHandle, state);
return;
}
//------------------------------------------------------------------------------
void nsPushMenu(nsIMenu * aMenu)
{
gPreviousMenuStack.InsertElementAt(aMenu, gPreviousMenuStack.Count());
}
//------------------------------------------------------------------------------
void nsPopMenu(nsIMenu ** aMenu)
{
*aMenu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1];
gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1);
}
//------------------------------------------------------------------------------
void nsPreviousMenuStackUnwind(nsIMenu * aMenuJustBuilt, MenuHandle aMenuHandleJustBuilt)
{
//printf("PreviousMenuStackUnwind called \n");
//printf("%d items on gPreviousMenuStack \n", gPreviousMenuStack.Count());
while (gPreviousMenuHandleStack.Count()) {
nsIMenu * menu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1];
MenuHandle menuHandle = (MenuHandle) gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1];
//printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count());
//printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count());
if( menu && menuHandle ) {
if( menuHandle != aMenuHandleJustBuilt ) {
nsCOMPtr<nsIMenuListener> listener(do_QueryInterface(menu));
if(listener) {
//printf("MenuPop \n");
nsMenuEvent mevent;
mevent.message = NS_MENU_SELECTED;
mevent.eventStructType = NS_MENU_EVENT;
mevent.point.x = 0;
mevent.point.y = 0;
mevent.widget = nsnull;
mevent.time = PR_IntervalNow();
mevent.mCommand = (PRUint32) nsnull;
// UNDO
listener->MenuDeselected(mevent);
gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1);
//printf("%d items now on gPreviousMenuStack \n", gPreviousMenuStack.Count());
gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1);
}
} else {
//printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count());
//printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count());
return;
}
}
}
//printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count());
//printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count());
}
//------------------------------------------------------------------------------
void nsPushMenuHandle(MenuHandle aMenu)
{
gPreviousMenuHandleStack.AppendElement(aMenu);
}
//------------------------------------------------------------------------------
void nsPopMenuHandle(MenuHandle * aMenu)
{
*aMenu = (MenuHandle) gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1];
gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1);
}
/*
//------------------------------------------------------------------------------
void TestPreviousMenuStackUnwind(nsIMenu * aMenuJustBuilt, MenuHandle aMenuHandleJustBuilt)
{
//printf("PreviousMenuStackUnwind called \n");
//printf("%d items on gPreviousMenuStack \n", gPreviousMenuStack.Count());
while (gPreviousMenuHandleStack.Count()) {
MenuHandle menuHandle = (MenuHandle) gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1];
//printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count());
if( menuHandle != aMenuHandleJustBuilt) {
::DeleteMenuItem(menuHandle, 3);
::DeleteMenuItem(menuHandle, 2);
::DeleteMenuItem(menuHandle, 1);
//printf("%d items now on gPreviousMenuStack \n", gPreviousMenuStack.Count());
gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1);
} else {
//printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count());
return;
}
}
//printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count());
}
//------------------------------------------------------------------------------
void TestPostBuild(nsIMenu * menu, MenuHandle theMenu, PRBool isChild)
{
// it is built now
if(isChild || (gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1] != theMenu)) {
PushMenuHandle(theMenu);
//printf("Push: %d items in gMenuHandleStack \n", gMenuHandleStack.Count());
}
}
//------------------------------------------------------------------------------
void TestBuild(MenuHandle theMenu, PRBool isChild)
{
// Add item
::InsertMenuItem(theMenu, "\pFooItem", 1);
// Add item with sub menu
::InsertMenuItem(theMenu, "\pSubmenu", 2);
if(theMenu == gLevel2HierMenu) {
gCurrentMenuDepth = 3;
} else if(theMenu == gLevel3HierMenu) {
gCurrentMenuDepth = 4;
} else if(theMenu == gLevel4HierMenu) {
gCurrentMenuDepth = 5;
} else if(theMenu == gLevel5HierMenu) {
gCurrentMenuDepth = 6;
} else {
gCurrentMenuDepth = 2;
}
::SetMenuItemHierarchicalID(theMenu, 2, gCurrentMenuDepth);
// Add fake item to sub menu so we get the size message
::DeleteMenuItem(::GetMenuHandle(gCurrentMenuDepth), 1);
::InsertMenuItem(::GetMenuHandle(gCurrentMenuDepth), "\pFakeItem", 1);
gCurrentMenuDepth--;
TestPostBuild(nsnull, theMenu, isChild);
}
*/
#pragma options align=reset