/*	XMenu.h
 *
 *		This contains the various menu handling classes. Both the
 *	Macintosh and Windows use an abstraction of a 'menu', so this
 *	wrappers that abstraction.
 */

/**********************************************************************

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

**********************************************************************/

#ifndef PandaWave_XMENU
#define PandaWave_XMENU

#include <XConfig.h>
#include <XDynArray.h>
#include <XHandle.h>

#if OPT_XWIN
#include <X11/Xlib.h>						// X specific
#endif

/**@name Menu Management
 *
 *		Menu management on the various platforms is a bit tricky. On
 *	the Macintosh, each application has a central menu bar which sits
 *	along the top of the screen. Windows, on the other hand, has one
 *	menu bar per window (for SDI-style apps) or one central menu bar
 *	(for MDI-style apps). And X Windows doesn't have a built-in
 *	menu processing mechanism; the style that is implemented by YAAF
 *	is an SDI-style application mechanism.
 *
 *		To complicate matters further, X Windows uses a different
 *	internal structure than Windows, which is different than the
 *	internal structure used by the Macintosh. In particular,
 *	menus are independant entities on the Macintosh, while on Windows
 *	and X Windows, menus are owned by their menu bars in a hierarchical
 *	data structure.
 *
 *		YAAF compromises this mechanism by creating separate menu
 *	bar and menu abstractions, where menus are owned by their menu
 *	bars. This permits us to access the menus in a menu bar in the
 *	most natural way, and hide the implementation differences between
 *	the three different operating system platforms on which YAAF
 *	resides.
 *
 *		YAAF also implements a mechanism which associates a 16-bit
 *	value with each menu item. This "menu command" is what YAAF
 *	eventually sends to the focus of the application (or the focus
 *	of the window where this menu resides on an SDI application)
 *	when the menu command is selected. Also, it is this command ID
 *	that YAAF uses to handle menu processing.
 */
 
//@{

/************************************************************************/
/*																		*/
/*	Class References													*/
/*																		*/
/************************************************************************/

class XGDispatch;

/************************************************************************/
/*																		*/
/*	Internal structures													*/
/*																		*/
/************************************************************************/

#if OPT_XWIN == 1

/*	XGSMenuItem
 *
 *		How a single item is stored in my XGMenu object. This is the data
 *	that is stored in the 'extra' data field of the XGStringList object.
 */

struct XGSMenuItem {
	short				fItemID;
	short				fAccelerator;
	short				fCheckmark;
	short				fEnabled;
};

#endif

/************************************************************************/
/*																		*/
/*	Menu Bar Objects													*/
/*																		*/
/************************************************************************/

/*$	XGMenu
 *
 *		This defines a single menu. This is an abstraction for a single
 *	menu in the menu bar, or for a single sub-menu. Through this object
 *	you may access the different items inside a menu, such as the text
 *	associated with each item, and the menu item's command ID.
 */

class XGMenu {
	public:
		/*
		 *	Custom Construction
		 */
		
#if OPT_MACOS == 1
								XGMenu(MenuHandle, bool dup = false);
#endif

#if OPT_WINOS == 1
								XGMenu(HMENU,HMENU par = NULL,short ix = 0);
#endif

#if OPT_XWIN
								XGMenu(unsigned char **);
#endif

		virtual					~XGMenu();
				
		/*
		 *	Menu attributes
		 */
		
		long					GetLength() const;
		void					InsertItem(long index);
		void					DeleteItem(long index);
		
		/*
		 *	Item attributes
		 */

		void					GetText(long index, char *str) const;
		void					SetText(long index, const char *str);
		short					GetItemID(long index) const;
		void					SetItemID(long index, short);
		XGMenu					*GetSubMenu(long index) const;
									
		/*
		 *	Check/Select attributes
		 */
		
		void					SetEnabled(long index, bool flag);
		void					SetCheckmark(long index, short mark);
		bool					EnableMenu(bool flag);

	private:
		XGPDynArray<XGMenu>		fMenuList;

#if OPT_MACOS == 1
		bool					fDuplicate;
		MenuHandle				fMenuHandle;
		XGSDynArray<short>		fMenuItemID;
#endif

#if OPT_WINOS == 1
		bool					fInstalled;
		HMENU					fMenuHandle;
		HMENU					fParMenu;
		short					fParIndex;
#endif

#if OPT_XWIN == 1
		short					GetCommand(char accel);
		XGStringList			fMenuData;
	friend class XGMenuPop;						// support for drawing
#endif

	friend class XGMenuBar;
};

/*$	XGMenuBar
 *
 *		This is the menu bar object. This is the abstraction of the
 *	menu bar inside of my application. This is attached to the window
 *	or is global, and cannot be swapped out with another one like me.
 */

class XGMenuBar {
	public:
	
		/*
		 *	Custom constructors that are OS dependant
		 */
	
#if OPT_MACOS == 1
								XGMenuBar();
#endif

#if OPT_WINOS == 1
								XGMenuBar(HWND,bool);
#endif

#if OPT_XWIN == 1
								XGMenuBar(Window);
#endif

		virtual					~XGMenuBar();
		
		
		/*
		 *	Top level menus
		 */
		
		
		/*$	XGMenuBar::GetLength
		 *
		 *		Gets the number of menus in this menu bar. This
		 *	only returns a count of the application defined menus,
		 *	and does not return in it's count the Window's Close Box
		 *	menu or the various Macintosh system menus.
		 */
		
		long					GetLength() const
									{
										return fMenuBar.Length();
									}
									
		/*$	XGMenuBar::GetMenu
		 *
		 *		Gets the specified menu. The index is zero based.
		 *	This returns one of the application menus, and cannot
		 *	be used to access Windows's 'Close Box' menu, or the
		 *	various system menus on the Macintosh.
		 */
		
		XGMenu					*GetMenu(long i) const
									{
										return fMenuBar[i];
									}
									
		char					GetAccelerator(short) const;
		void					SetAccelerator(short,char);
		
		bool					LoadFromResource(short);

		/*
		 *	Menu command processing
		 */
		
		void					UpdateMenuBar(XGDispatch *);

#if (OPT_MACOS == 1)
		bool					MenuSelect(short, short);
		bool					MenuCommand(long);
#endif

#if (OPT_MACOS == 1) || (OPT_XWIN == 1)
		bool					MenuKey(char);
#endif

#if (OPT_WINOS == 1)
		bool					MenuCommand(WPARAM);
		static long				TranslateAccelerator(HWND,LPMSG);
#endif

#if OPT_XWIN == 1
		bool					MenuDispatch(short);
		void					GetMenuName(short i, char *data)
									{
										fMenuList.GetString(i,data);
									}
#endif

	private:
	
		/*
		 *	Internal stuff for management
		 */
		
		short					fMenuBarID;
		bool					fMark;
		XGPDynArray<XGMenu>		fMenuBar;
		
		bool					UpdateMenu(XGMenu *, XGDispatch *);
		static XGMenu			*FindByCommand(XGMenu *, short, short *);
		XGMenu					*FindByCommand(short,short *) const;
		
#if OPT_MACOS == 1
		static XGMenu			*FindByMenuID(XGMenu *, short);
		XGMenu					*FindByMenuID(short) const;
#endif

#if OPT_WINOS == 1
		bool					fMDIFlag;
		HWND					fWindow;
		static HACCEL			gAccel;
		static bool				gAccelRes;
		static long				gAccelRef;
#endif

#if OPT_XWIN == 1
		XGStringList			fMenuList;
		Window					fWindow;
#endif
};

//@}

#endif /* PandaWave_XMENU */
