/******************************************************************************
 JXTextMenuData.h

	Interface for the JXTextMenuData class

	Copyright © 1996 by John Lindal. All rights reserved.

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

#ifndef _H_JXTextMenuData
#define _H_JXTextMenuData

#include <JXMenuData.h>
#include <JFontStyle.h>
#include <JRunArray.h>

class JFontManager;
class JXImage;
class JXTextMenu;
class JXTextMenuTable;

class JXTextMenuData : public JXMenuData
{
public:

	JXTextMenuData(JXTextMenu* menu);

	virtual ~JXTextMenuData();

	void			InsertItem(const JIndex index, const JCharacter* str,
							   const JBoolean isCheckbox = kFalse,
							   const JBoolean isRadio = kFalse,
							   const JCharacter* shortcuts = NULL,
							   const JCharacter* nmShortcut = NULL,
							   const JCharacter* id = NULL);
	void			PrependItem(const JCharacter* str,
								const JBoolean isCheckbox = kFalse,
								const JBoolean isRadio = kFalse,
								const JCharacter* shortcuts = NULL,
								const JCharacter* nmShortcut = NULL,
								const JCharacter* id = NULL);
	void			AppendItem(const JCharacter* str,
							   const JBoolean isCheckbox = kFalse,
							   const JBoolean isRadio = kFalse,
							   const JCharacter* shortcuts = NULL,
							   const JCharacter* nmShortcut = NULL,
							   const JCharacter* id = NULL);
	virtual void	DeleteItem(const JIndex index);		// must call inherited
	virtual void	DeleteAll();						// must call inherited

	const JString&	GetText(const JIndex index) const;
	void			SetText(const JIndex index, const JCharacter* str);
	void			SetMenuItems(const JCharacter* menuStr);

	const JCharacter*	GetFontName(const JIndex index) const;
	JSize				GetFontSize(const JIndex index) const;
	JFontStyle			GetFontStyle(const JIndex index) const;
	void				GetFont(const JIndex index, JString* name,
								JSize* size, JFontStyle* style) const;

	void	SetFontName(const JIndex index, const JCharacter* name);
	void	SetFontSize(const JIndex index, const JSize size);
	void	SetFontStyle(const JIndex index, const JFontStyle& style);
	void	SetFont(const JIndex index, const JCharacter* name,
					const JSize size, const JFontStyle& style = JFontStyle());
	void	SetFont(const JIndex index, const JFontID id,
					const JSize size, const JFontStyle& style = JFontStyle());

	JBoolean	GetImage(const JIndex index, const JXImage** image) const;
	void		SetImage(const JIndex index, JXImage* image,
						 const JBoolean menuOwnsImage);
	void		ClearImage(const JIndex index);

	JBoolean	GetNMShortcut(const JIndex index, JString* str) const;
	void		SetNMShortcut(const JIndex index, const JCharacter* str);

	JBoolean	HasSeparator(const JIndex index) const;
	void		ShowSeparatorAfter(const JIndex index, const JBoolean show = kTrue);

	JBoolean	HeightCompressed() const;
	void		CompressHeight(const JBoolean compress = kTrue);

	// called by JXTextMenuTable

	void	ConfigureTable(JXTextMenuTable* table);

	const JString&	GetText(const JIndex index, JIndex* ulIndex,
							JFontID* id, JSize* size, JFontStyle* style) const;
	JBoolean		GetNMShortcut(const JIndex index, JString* str, JFontID* id,
								  JSize* size, JFontStyle* style) const;

	static void	TranslateModifierName(JString* nmShortcut);

protected:

	virtual void	ItemShortcutsChanged(const JIndex index, const JString* shortcuts);

private:

	struct TextItemData
	{
		JString*	text;
		JIndex		ulIndex;
		JString*	nmShortcut;			// can be NULL
		JFontID		fontID;
		JSize		fontSize;
		JFontStyle	fontStyle;
		JXImage*	image;				// can be NULL
		JBoolean	ownsImage;			// kTrue if we should delete image
		JBoolean	separator;			// kTrue if item is followed by separator

		TextItemData()
			:
			text( NULL ), ulIndex( 0 ), nmShortcut( NULL ),
			fontID( 0 ), fontSize( 0 ), fontStyle(),
			image( NULL ), ownsImage( kTrue ), separator( kFalse )
		{ };

		TextItemData(JString* str)
			:
			text( str ), ulIndex( 0 ), nmShortcut( NULL ),
			fontID( 0 ), fontSize( 0 ), fontStyle(),
			image( NULL ), ownsImage( kTrue ), separator( kFalse )
		{ };
	};

private:

	JXTextMenu*				itsMenu;		// it owns us
	const JFontManager*		itsFontMgr;
	JArray<TextItemData>*	itsTextItemData;

	JBoolean				itsNeedGeomRecalcFlag;
	JCoordinate				itsMaxImageWidth;
	JCoordinate				itsMaxTextWidth;
	JCoordinate				itsMaxShortcutWidth;
	JBoolean				itsHasNMShortcutsFlag;
	JBoolean				itsCompressHeightFlag;
	JRunArray<JCoordinate>*	itsItemHeights;

private:

	void	ParseMenuItemStr(JString* text, JBoolean* isActive,
							 JBoolean* hasSeparator, JBoolean* isCheckbox,
							 JBoolean* isRadio, JString* shortcuts,
							 JString* nmShortcut, JString* id) const;
	void	CleanOutTextItem(TextItemData* itemData);

	JBoolean	ParseNMShortcut(const JString& str, int* key,
								JXKeyModifiers* modifiers);

	// not allowed

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

public:

	// JBroadcaster messages

	static const JCharacter* kImageChanged;

	class ImageChanged : public JBroadcaster::Message
		{
		public:

			ImageChanged(const JIndex index)
				:
				JBroadcaster::Message(kImageChanged),
				itsIndex(index)
			{ };

			JIndex
			GetIndex() const
			{
				return itsIndex;
			};

		private:

			JIndex itsIndex;
		};
};


/******************************************************************************
 New item

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

inline void
JXTextMenuData::PrependItem
	(
	const JCharacter*	str,
	const JBoolean		isCheckbox,
	const JBoolean		isRadio,
	const JCharacter*	shortcuts,
	const JCharacter*	nmShortcut,
	const JCharacter*	id
	)
{
	InsertItem(1, str, isCheckbox, isRadio, shortcuts, nmShortcut, id);
}

inline void
JXTextMenuData::AppendItem
	(
	const JCharacter*	str,
	const JBoolean		isCheckbox,
	const JBoolean		isRadio,
	const JCharacter*	shortcuts,
	const JCharacter*	nmShortcut,
	const JCharacter*	id
	)
{
	InsertItem(GetElementCount()+1, str, isCheckbox, isRadio, shortcuts, nmShortcut, id);
}

/******************************************************************************
 GetText

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

inline const JString&
JXTextMenuData::GetText
	(
	const JIndex index
	)
	const
{
	const TextItemData itemData = itsTextItemData->GetElement(index);
	return *(itemData.text);
}

/******************************************************************************
 Get font

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

inline JSize
JXTextMenuData::GetFontSize
	(
	const JIndex index
	)
	const
{
	const TextItemData itemData = itsTextItemData->GetElement(index);
	return itemData.fontSize;
}

inline JFontStyle
JXTextMenuData::GetFontStyle
	(
	const JIndex index
	)
	const
{
	const TextItemData itemData = itsTextItemData->GetElement(index);
	return itemData.fontStyle;
}

/******************************************************************************
 HasSeparator

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

inline JBoolean
JXTextMenuData::HasSeparator
	(
	const JIndex index
	)
	const
{
	const TextItemData itemData = itsTextItemData->GetElement(index);
	return itemData.separator;
}

/******************************************************************************
 Compress height

	This takes effect next time the menu is displayed.

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

inline JBoolean
JXTextMenuData::HeightCompressed()
	const
{
	return itsCompressHeightFlag;
}

inline void
JXTextMenuData::CompressHeight
	(
	const JBoolean compress
	)
{
	if (itsCompressHeightFlag != compress)
		{
		itsCompressHeightFlag = compress;
		itsNeedGeomRecalcFlag = kTrue;
		}
}

#endif
