/******************************************************************************
 JXMenu.h

	Interface for the JXMenu class

	Copyright © 1996-98 by John Lindal. All rights reserved.

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

#ifndef _H_JXMenu
#define _H_JXMenu

#include <JXWidget.h>
#include <JFontStyle.h>

class JString;
class JXMenuData;
class JXMenuBar;
class JXMenuManager;
class JXWindowDirector;
class JXMenuDirector;
class JXMenuTable;
class JXImage;

class JXToolBar;
class JXTextMenu;
class JXImageMenu;

class JXMenu : public JXWidget
{
	friend class JXMenuData;
	friend class JXMenuTable;
	friend class JXMenuBar;
	friend class JXMenuManager;

	friend class JXToolBar;

public:

	enum UpdateAction
	{
		kDisableNone,
		kDisableSingles,	// disable items without submenus before update message (default)
		kDisableAll			// disable everything before update message
	};

	enum Style
	{
		kMacintoshStyle,
		kWindowsStyle
	};

	enum ArrowPosition
	{
		kArrowAtLeft,
		kArrowAtRight		// default
	};

public:

	JXMenu(const JCharacter* title, JXContainer* enclosure,
		   const HSizingOption hSizing, const VSizingOption vSizing,
		   const JCoordinate x, const JCoordinate y,
		   const JCoordinate w, const JCoordinate h);

	JXMenu(JXImage* image, const JBoolean menuOwnsImage, JXContainer* enclosure,
		   const HSizingOption hSizing, const VSizingOption vSizing,
		   const JCoordinate x, const JCoordinate y,
		   const JCoordinate w, const JCoordinate h);

	JXMenu(JXMenu* owner, const JIndex itemIndex, JXContainer* enclosure);

	virtual ~JXMenu();

	JBoolean	IsOpen() const;

	const JString&	GetTitle() const;
	void			SetTitle(const JCharacter* title);

	void	SetTitleFontName(const JCharacter* fontName);
	void	SetTitleFontSize(const JSize size);
	void	SetTitleFontStyle(const JFontStyle& style);

	const JXImage*	GetTitleImage() const;
	void			SetTitleImage(JXImage* image, const JBoolean menuOwnsImage);

	void	SetShortcuts(const JCharacter* list);

	JBoolean	IsEmpty() const;
	JSize		GetItemCount() const;
	void		DeleteItem(const JIndex index);
	void		RemoveAllItems();

	void	SetItemShortcuts(const JIndex index, const JCharacter* shortcuts);

	JBoolean	GetItemID(const JIndex index, const JString** id) const;
	void		SetItemID(const JIndex index, const JCharacter* id);
	JBoolean	ItemIDToIndex(const JCharacter* targetID, JIndex* index) const;

	void	EnableItem(const JIndex index);
	void	EnableAll();
	void	DisableItem(const JIndex index);
	void	DisableAll();
	void	SetItemEnable(const JIndex index, const JBoolean enabled);

	void		CheckItem(const JIndex index);
	JBoolean	IsChecked(const JIndex index) const;

	void		AttachSubmenu(const JIndex index, JXMenu* submenu);
	JBoolean	RemoveSubmenu(const JIndex index, JXMenu** theMenu);
	void		DeleteSubmenu(const JIndex index);
	JBoolean	GetSubmenu(const JIndex index, const JXMenu** menu) const;

	void		SetUpdateAction(const UpdateAction action);

	JBoolean	IsPopupChoice() const;
	void		SetToPopupChoice(const JBoolean isPopup,
								 const JIndex initialChoice);
	void		SetPopupChoice(const JIndex index);

	virtual void	Activate();
	virtual void	Deactivate();

	JBoolean	IsHiddenPopupMenu() const;
	void		SetToHiddenPopupMenu(const JBoolean isHiddenPopup);
	JBoolean	PopUp(JXContainer* mouseOwner, const JPoint& pt,
					  const JXButtonStates&	buttonStates,
					  const JXKeyModifiers&	modifiers);

	JBoolean	GetMenuBar(JXMenuBar** menuBar) const;
	JXMenu*		GetTopLevelMenu() const;

	ArrowPosition	GetPopupArrowPosition() const;
	void			SetPopupArrowPosition(const ArrowPosition pos);

	virtual JBoolean	IsMenu() const;

	virtual void	HandleShortcut(const int key, const JXKeyModifiers& modifiers);

	// provides safe downcasting

	virtual JXTextMenu*			CastToJXTextMenu();
	virtual const JXTextMenu*	CastToJXTextMenu() const;

	virtual JXImageMenu*		CastToJXImageMenu();
	virtual const JXImageMenu*	CastToJXImageMenu() const;

protected:

	void		SetBaseItemData(JXMenuData* baseItemData);
	void		ClearBaseItemData();
	JBoolean	PrepareToOpenMenu();

	virtual JXMenuDirector*	CreateWindow(JXWindowDirector* supervisor) = 0;
	virtual void			AdjustPopupChoiceTitle(const JIndex index) = 0;

	virtual void	Draw(JXWindowPainter& p, const JRect& rect);
	virtual void	DrawBorder(JXWindowPainter& p, const JRect& frame);

	virtual void	HandleMouseDown(const JPoint& pt, const JXMouseButton button,
									const JSize clickCount,
									const JXButtonStates& buttonStates,
									const JXKeyModifiers& modifiers);

	virtual void	Receive(JBroadcaster* sender, const Message& message);

	// called by JXMenuTable

	void	BroadcastSelection(const JIndex itemIndex);

private:

	JString*	itsTitle;
	JXImage*	itsTitleImage;			// can be NULL
	JBoolean	itsOwnsTitleImageFlag;	// kTrue => we delete it
	JString*	itsShortcuts;			// can be NULL
	JIndex		itsULIndex;
	JXMenuData*	itsBaseItemData;		// derived class owns this
	JXMenuBar*	itsMenuBar;				// can be NULL; if there is one, it owns us
	JXMenu*		itsOwner;				// NULL if top level menu

	JString*	itsTitleFontName;
	JSize		itsTitleSize;
	JFontStyle	itsTitleStyle;
	JColorIndex	itsTrueTitleColor;		// saves title color while deactivated
	JBoolean	itsShouldBeActiveFlag;	// kTrue  => last client call was Activate()
	JBoolean	itsUpdateSBAFlag;		// kFalse => don't change itsShouldBeActiveFlag
	JSize		itsMinWidth;

	UpdateAction	itsUpdateAction;
	JBoolean		itsIsPopupChoiceFlag;
	JBoolean		itsIsHiddenPopupMenuFlag;

	ArrowPosition	itsArrowPosition;	// where arrow is drawn when menu is free-standing

	// used when menu is pulled down

	JXMenuDirector*	itsMenuDirector;
	JBoolean		itsCloseAfterSelectionFlag;	// kTrue => close menu in BroadcastSelection()

private:

	void	JXMenuX(const JCharacter* title, JXImage* image,
					const JBoolean menuOwnsImage);
	void	RemoveSubmenu(JXMenu* theMenu);
	void	SetOwner(JXMenu* owner);
	void	AdjustAppearance();
	void	AdjustAppearance(const JCoordinate minWidth);

	JBoolean	Open(const JPoint& leftPtR = JPoint(),
					 const JPoint& rightPtR = JPoint());
	void		Close();

	// called by JXMenuBar

	void	SetMenuBar(JXMenuBar* bar);

	// not allowed

	JXMenu(const JXMenu& source);
	const JXMenu& operator=(const JXMenu& source);

public:

	// JBroadcaster messages

	static const JCharacter* kNeedsUpdate;
	static const JCharacter* kItemSelected;

	class NeedsUpdate : public JBroadcaster::Message
		{
		public:

			NeedsUpdate()
				:
				JBroadcaster::Message(kNeedsUpdate)
				{ };
		};

	class ItemSelected : public JBroadcaster::Message
		{
		public:

			ItemSelected(const JIndex index)
				:
				JBroadcaster::Message(kItemSelected),
				itsIndex(index)
				{ };

			JIndex
			GetIndex() const
			{
				return itsIndex;
			};

		private:

			JIndex	itsIndex;
		};
};


/******************************************************************************
 IsOpen

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

inline JBoolean
JXMenu::IsOpen()
	const
{
	return JConvertToBoolean( itsMenuDirector != NULL );
}

/******************************************************************************
 GetTitle

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

inline const JString&
JXMenu::GetTitle()
	const
{
	return *itsTitle;
}

/******************************************************************************
 GetTitleImage

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

inline const JXImage*
JXMenu::GetTitleImage()
	const
{
	return itsTitleImage;
}

/******************************************************************************
 SetUpdateAction

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

inline void
JXMenu::SetUpdateAction
	(
	const UpdateAction action
	)
{
	itsUpdateAction = action;
}

/******************************************************************************
 PopupChoice

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

inline JBoolean
JXMenu::IsPopupChoice()
	const
{
	return itsIsPopupChoiceFlag;
}

inline void
JXMenu::SetToPopupChoice
	(
	const JBoolean	isPopup,
	const JIndex	initialChoice
	)
{
	itsIsPopupChoiceFlag = isPopup;
	AdjustPopupChoiceTitle(initialChoice);
}

inline void
JXMenu::SetPopupChoice
	(
	const JIndex index
	)
{
	if (itsIsPopupChoiceFlag)
		{
		AdjustPopupChoiceTitle(index);
		}
}

/******************************************************************************
 HiddenPopupMenu

	You must explicitly tell us if the menu is an invisible popup menu,
	because invisible menus are normally disabled.

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

inline JBoolean
JXMenu::IsHiddenPopupMenu()
	const
{
	return itsIsHiddenPopupMenuFlag;
}

inline void
JXMenu::SetToHiddenPopupMenu
	(
	const JBoolean isHiddenPopup
	)
{
	itsIsHiddenPopupMenuFlag = isHiddenPopup;
}

/******************************************************************************
 GetPopupArrowPosition

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

inline JXMenu::ArrowPosition
JXMenu::GetPopupArrowPosition()
	const
{
	return itsArrowPosition;
}

/******************************************************************************
 SetPopupArrowPosition

	Set the position of the down arrow when the menu is not in a menu bar.

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

inline void
JXMenu::SetPopupArrowPosition
	(
	const ArrowPosition pos
	)
{
	itsArrowPosition = pos;
	Refresh();
}

/******************************************************************************
 AdjustAppearance (private)

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

inline void
JXMenu::AdjustAppearance()
{
	AdjustAppearance(itsMinWidth);
}

#endif
