/** 
 * @file llmenugl.h
 * @brief Declaration of the opengl based menu system.
 *
 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_LLMENUGL_H
#define LL_LLMENUGL_H

#include <list>

#include "llstring.h"
#include "v4color.h"
#include "llframetimer.h"

#include "llkeyboard.h"
#include "llfloater.h"
#include "lluistring.h"
#include "llview.h"
#include <boost/function.hpp>

extern S32 MENU_BAR_HEIGHT;
extern S32 MENU_BAR_WIDTH;

class LLMenuKeyboardBinding
{
public:
    KEY				mKey;
    MASK			mMask;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemGL
//
// The LLMenuItemGL represents a single menu item in a menu. 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl
{
public:
	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
	{
		Optional<std::string>	shortcut;
		Optional<KEY>			jump_key;
		Optional<bool>			use_mac_ctrl,
								allow_key_repeat;

		Ignored					rect,
								left,
								top,
								right,
								bottom,
								width,
								height,
								bottom_delta,
								left_delta;

		Optional<LLUIColor>		enabled_color,
								disabled_color,
								highlight_bg_color,
								highlight_fg_color;


		Params();
	};

protected:
	LLMenuItemGL(const Params&);
	friend class LLUICtrlFactory;
public:
	// LLView overrides
	/*virtual*/ void onVisibilityChange(bool new_visibility);
	/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);
	/*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask);
	/*virtual*/ bool handleRightMouseUp(S32 x, S32 y, MASK mask);

	// LLUICtrl overrides
	/*virtual*/ void setValue(const LLSD& value);
	/*virtual*/ LLSD getValue() const;

	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
	virtual bool handleAcceleratorKey(KEY key, MASK mask);

	LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); }

	void setJumpKey(KEY key);
	KEY getJumpKey() const { return mJumpKey; }
	
	// set the font used by this item.
	void setFont(const LLFontGL* font) { mFont = font; }
	const LLFontGL* getFont() const { return mFont; }

	// returns the height in pixels for the current font.
	virtual U32 getNominalHeight( void ) const;
	
	// Marks item as not needing space for check marks or accelerator keys
	virtual void setBriefItem(bool brief);
	virtual bool isBriefItem() const;

	virtual bool addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp);
	void setAllowKeyRepeat(bool allow) { mAllowKeyRepeat = allow; }
	bool getAllowKeyRepeat() const { return mAllowKeyRepeat; }

	// change the label
	void setLabel( const LLStringExplicit& label ) { mLabel = label; }	
	std::string getLabel( void ) const { return mLabel.getString(); }
	virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text );

	// Get the parent menu for this item
	virtual class LLMenuGL*	getMenu() const;

	// returns the normal width of this control in pixels - this is
	// used for calculating the widest item, as well as for horizontal
	// arrangement.
	virtual U32 getNominalWidth( void ) const;

	// buildDrawLabel() - constructs the string used during the draw()
	// function. This reduces the overall string manipulation, but can
	// lead to visual errors if the state of the object changes
	// without the knowledge of the menu item. For example, if a
	// boolean being watched is changed outside of the menu item's
	// onCommit() function, the draw buffer will not be updated and will
	// reflect the wrong value. If this ever becomes an issue, there
	// are ways to fix this.
	// Returns the enabled state of the item.
	virtual void buildDrawLabel( void );

	// for branching menu items, bring sub menus up to root level of menu hierarchy
	virtual void updateBranchParent( LLView* parentp ){};
	
	virtual void onCommit( void );

	virtual void setHighlight( bool highlight );
	virtual bool getHighlight() const { return mHighlight; }

	// determine if this represents an active sub-menu
	virtual bool isActive( void ) const { return false; }

	// determine if this represents an open sub-menu
	virtual bool isOpen( void ) const { return false; }

	virtual void setEnabledSubMenus(bool enable){};

	// LLView Functionality
	virtual bool handleKeyHere( KEY key, MASK mask );
	virtual bool handleMouseDown( S32 x, S32 y, MASK mask );
	virtual bool handleMouseUp( S32 x, S32 y, MASK mask );
	virtual bool handleScrollWheel( S32 x, S32 y, S32 clicks );

	virtual void	onMouseEnter(S32 x, S32 y, MASK mask);
	virtual void	onMouseLeave(S32 x, S32 y, MASK mask);

	virtual void draw( void );

	bool getHover() const { return mGotHover; }

	void setDrawTextDisabled(bool disabled) { mDrawTextDisabled = disabled; }
	bool getDrawTextDisabled() const { return mDrawTextDisabled; }

protected:
	void setHover(bool hover) { mGotHover = hover; }

	// This function appends the character string representation of
	// the current accelerator key and mask to the provided string.
	void appendAcceleratorString( std::string& st ) const;

	virtual std::string _getSearchText() const
	{
		return mLabel.getString();
	}

protected:
	KEY mAcceleratorKey;
	MASK mAcceleratorMask;
	// mLabel contains the actual label specified by the user.
	LLUIString mLabel;

	// The draw labels contain some of the labels that we draw during
	// the draw() routine. This optimizes away some of the string
	// manipulation.
	LLUIString mDrawBoolLabel;
	LLUIString mDrawAccelLabel;
	LLUIString mDrawBranchLabel;

	LLUIColor mEnabledColor;
	LLUIColor mDisabledColor;
	LLUIColor mHighlightBackground;
	LLUIColor mHighlightForeground;

	bool mHighlight;
private:
	// Keyboard and mouse variables
	bool mAllowKeyRepeat;
	bool mGotHover;

	// If true, suppress normal space for check marks on the left and accelerator
	// keys on the right.
	bool mBriefItem;

	// Font for this item
	const LLFontGL* mFont;
	bool mDrawTextDisabled;

	KEY mJumpKey;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemSeparatorGL
//
// This class represents a separator.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuItemSeparatorGL : public LLMenuItemGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
	{
        Optional<EnableCallbackParam > on_visible;
        Params();
	};

    LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params());

	/*virtual*/ void draw( void );
	/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
	/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask);
	/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);

    virtual void buildDrawLabel();

	/*virtual*/ U32 getNominalHeight( void ) const;

private:
    enable_signal_t mVisibleSignal;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemCallGL
//
// The LLMenuItemCallerGL represents a single menu item in a menu that
// calls a user defined callback.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LLMenuItemCallGL : public LLMenuItemGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
	{
		Optional<EnableCallbackParam > on_enable;
		Optional<CommitCallbackParam > on_click;
		Optional<EnableCallbackParam > on_visible;
		Params()
			: on_enable("on_enable"),
			  on_click("on_click"),
			  on_visible("on_visible")
		{}
	};
protected:
	LLMenuItemCallGL(const Params&);
	friend class LLUICtrlFactory;
	void updateEnabled( void );
	void updateVisible( void );

public:
	void initFromParams(const Params& p);
	
	// called to rebuild the draw label
	virtual void buildDrawLabel( void );

	virtual void onCommit( void );

	virtual bool handleAcceleratorKey(KEY key, MASK mask);
	virtual bool handleKeyHere(KEY key, MASK mask);
	
	//virtual void draw();
	
	boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb )
	{
		return setCommitCallback(cb);
	}
	
	boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb )
	{
		return mEnableSignal.connect(cb);
	}
		
private:
	enable_signal_t mEnableSignal;
	enable_signal_t mVisibleSignal;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemCheckGL
//
// The LLMenuItemCheckGL is an extension of the LLMenuItemCallGL
// class, by allowing another method to be specified which determines
// if the menu item should consider itself checked as true or not.  Be
// careful that the provided callback is fast - it needs to be VERY
// EFFICIENT because it may need to be checked a lot.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LLMenuItemCheckGL 
:	public LLMenuItemCallGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
	{
		Optional<EnableCallbackParam > on_check;
		Params()
		:	on_check("on_check")
		{}
	};

protected:
	LLMenuItemCheckGL(const Params&);
	friend class LLUICtrlFactory;
public:
	
	void initFromParams(const Params& p);

	virtual void onCommit( void );
	
	virtual void setValue(const LLSD& value);
	virtual LLSD getValue() const;

	// called to rebuild the draw label
	virtual void buildDrawLabel( void );
	
	boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb )
	{
		return mCheckSignal.connect(cb);
	}
	
private:
	enable_signal_t mCheckSignal;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuGL
//
// The Menu class represents a normal rectangular menu somewhere on
// screen. A Menu can have menu items (described above) or sub-menus
// attached to it. Sub-menus are implemented via a specialized
// menu-item type known as a branch. Since it's easy to do wrong, I've
// taken the branch functionality out of public view, and encapsulate
// it in the appendMenu() method.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// child widget registry
struct MenuRegistry : public LLChildRegistry<MenuRegistry>
{
	LLSINGLETON_EMPTY_CTOR(MenuRegistry);
};


class LLMenuGL 
:	public LLUICtrl
{
public:
	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
	{
		Optional<KEY>					jump_key;
		Optional<bool>					horizontal_layout,
										can_tear_off,
										drop_shadow,
										bg_visible,
										create_jump_keys,
										keep_fixed_size,
										scrollable;
		Optional<U32>					max_scrollable_items;
		Optional<U32>					preferred_width;
		Optional<LLUIColor>				bg_color;
		Optional<S32>					shortcut_pad;

		Params()
		:	jump_key("jump_key", KEY_NONE),
			horizontal_layout("horizontal_layout"),
			can_tear_off("tear_off", false),
			drop_shadow("drop_shadow", true),
			bg_visible("bg_visible", true),
			create_jump_keys("create_jump_keys", false),
			keep_fixed_size("keep_fixed_size", false),
			bg_color("bg_color",  LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )),
			scrollable("scrollable", false), 
			max_scrollable_items("max_scrollable_items", U32_MAX),
			preferred_width("preferred_width", U32_MAX),
			shortcut_pad("shortcut_pad")
		{
			addSynonym(bg_visible, "opaque");
			addSynonym(bg_color, "color");
			addSynonym(can_tear_off, "can_tear_off");
		}
	};

	// my valid children are contained in MenuRegistry
	typedef MenuRegistry child_registry_t;

	void initFromParams(const Params&);

	// textual artwork which menugl-imitators may want to match
	static const std::string BOOLEAN_TRUE_PREFIX;
	static const std::string BRANCH_SUFFIX;
	static const std::string ARROW_UP;
	static const std::string ARROW_DOWN;

	// for scrollable menus
	typedef enum e_scrolling_direction
	{
		SD_UP = 0,
		SD_DOWN = 1,
		SD_BEGIN = 2,
		SD_END = 3
	} EScrollingDirection;

protected:
	LLMenuGL(const LLMenuGL::Params& p);
	friend class LLUICtrlFactory;
	// let branching menu items use my protected traversal methods
	friend class LLMenuItemBranchGL;
public:
	virtual ~LLMenuGL( void );

	void parseChildXML(LLXMLNodePtr child, LLView* parent);

	// LLView Functionality
	/*virtual*/ bool handleUnicodeCharHere( llwchar uni_char );
	/*virtual*/ bool handleHover( S32 x, S32 y, MASK mask );
	/*virtual*/ bool handleScrollWheel( S32 x, S32 y, S32 clicks );
	/*virtual*/ void draw( void );
	/*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha);
	/*virtual*/ void setVisible(bool visible);
	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
    /*virtual*/ void deleteAllChildren();
	/*virtual*/ void removeChild( LLView* ctrl);
	/*virtual*/ bool postBuild();
	
	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
	virtual bool handleAcceleratorKey(KEY key, MASK mask);

	LLMenuGL* findChildMenuByName(const std::string& name, bool recurse) const;
	
	bool clearHoverItem();

	// return the name label
	const std::string& getLabel( void ) const { return mLabel.getString(); }
	void setLabel(const LLStringExplicit& label) { mLabel = label; }

	// background colors
	void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; }
	const LLUIColor& getBackgroundColor() const { return mBackgroundColor; }
	void setBackgroundVisible( bool b )	{ mBgVisible = b; }
	void setCanTearOff(bool tear_off);

	// add a separator to this menu
	virtual bool addSeparator();

	// for branching menu items, bring sub menus up to root level of menu hierarchy
	virtual void updateParent( LLView* parentp );

	// setItemEnabled() - pass the name and the enable flag for a
	// menu item. true will make sure it's enabled, false will disable
	// it.
	void setItemEnabled( const std::string& name, bool enable ); 
	
	// propagate message to submenus
	void setEnabledSubMenus(bool enable);

	void setItemVisible( const std::string& name, bool visible);

    void setItemLabel(const std::string &name, const std::string &label);
	
	// sets the left,bottom corner of menu, useful for popups
	void setLeftAndBottom(S32 left, S32 bottom);

	virtual bool handleJumpKey(KEY key);

	virtual bool jumpKeysActive();

	virtual bool isOpen();

	void needsArrange() { mNeedsArrange = true; }
	// Shape this menu to fit the current state of the children, and
	// adjust the child rects to fit. This is called automatically
	// when you add items. *FIX: We may need to deal with visibility
	// arrangement.
	virtual void arrange( void );
	void arrangeAndClear( void );

	// remove all items on the menu
	void empty( void );

	// erase group of items from menu
	void erase( S32 begin, S32 end, bool arrange = true );

	// add new item at position
	void insert( S32 begin, LLView * ctrl, bool arrange = true );

	void			setItemLastSelected(LLMenuItemGL* item);	// must be in menu
	U32				getItemCount();				// number of menu items
	LLMenuItemGL*	getItem(S32 number);		// 0 = first item
    LLMenuItemGL*   getItem(std::string name);
	LLMenuItemGL*	getHighlightedItem();				

	LLMenuItemGL*	highlightNextItem(LLMenuItemGL* cur_item, bool skip_disabled = true);
	LLMenuItemGL*	highlightPrevItem(LLMenuItemGL* cur_item, bool skip_disabled = true);

	void buildDrawLabels();
	void createJumpKeys();

	// Show popup at a specific location, in the spawn_view's coordinate frame
	static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0);

	// Whether to drop shadow menu bar 
	void setDropShadowed( const bool shadowed );

	void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); }
	LLMenuItemGL* getParentMenuItem() const { return dynamic_cast<LLMenuItemGL*>(mParentMenuItem.get()); }

	void setTornOff(bool torn_off);
	bool getTornOff() { return mTornOff; }

	bool getCanTearOff() { return mTearOffItem != NULL; }

	KEY getJumpKey() const { return mJumpKey; }
	void setJumpKey(KEY key) { mJumpKey = key; }

	static void setKeyboardMode(bool mode) { sKeyboardMode = mode; }
	static bool getKeyboardMode() { return sKeyboardMode; }

	S32 getShortcutPad() { return mShortcutPad; }

	bool scrollItems(EScrollingDirection direction);
	bool isScrollable() const { return mScrollable; }

	static class LLMenuHolderGL* sMenuContainer;
	
	void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; }
	bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; }

	void setAlwaysShowMenu(bool show) { mAlwaysShowMenu = show; }
	bool getAlwaysShowMenu() { return mAlwaysShowMenu; }

	// add a context menu branch
	bool appendContextSubMenu(LLMenuGL *menu);

protected:
	void createSpilloverBranch();
	void cleanupSpilloverBranch();
	// Add the menu item to this menu.
	virtual bool append( LLMenuItemGL* item );

	// add a menu - this will create a cascading menu
	virtual bool appendMenu( LLMenuGL* menu );

	// Used in LLContextMenu and in LLTogleableMenu
	// to add an item of context menu branch
	bool addContextChild(LLView* view, S32 tab_group);

	// TODO: create accessor methods for these?
	typedef std::list< LLMenuItemGL* > item_list_t;
	item_list_t mItems;
	LLMenuItemGL*mFirstVisibleItem;
	LLMenuItemGL *mArrowUpItem, *mArrowDownItem;

	typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t;
	navigation_key_map_t mJumpKeys;
	S32				mLastMouseX;
	S32				mLastMouseY;
	S32				mMouseVelX;
	S32				mMouseVelY;
	U32				mMaxScrollableItems;
	U32				mPreferredWidth;
	bool			mHorizontalLayout;
	bool			mScrollable;
	bool			mKeepFixedSize;
	bool			mNeedsArrange;

private:


	static LLColor4 sDefaultBackgroundColor;
	static bool		sKeyboardMode;

	bool			mAlwaysShowMenu;

	LLUIColor		mBackgroundColor;
	bool			mBgVisible;
	LLHandle<LLView> mParentMenuItem;
	LLUIString		mLabel;
	bool mDropShadowed; 	//  Whether to drop shadow 
	bool			mHasSelection;
	LLFrameTimer	mFadeTimer;
	LLTimer			mScrollItemsTimer;
	bool			mTornOff;
	class LLMenuItemTearOffGL* mTearOffItem;
	class LLMenuItemBranchGL* mSpilloverBranch;
	LLMenuGL*		mSpilloverMenu;
	KEY				mJumpKey;
	bool			mCreateJumpKeys;
	S32				mShortcutPad;
	bool			mResetScrollPositionOnShow;
}; // end class LLMenuGL



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemBranchGL
//
// The LLMenuItemBranchGL represents a menu item that has a
// sub-menu. This is used to make cascading menus.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LLMenuItemBranchGL : public LLMenuItemGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
	{
		Optional<LLMenuGL*>	branch;
	};

protected:
	LLMenuItemBranchGL(const Params&);
	friend class LLUICtrlFactory;
public:
	virtual ~LLMenuItemBranchGL();
	
	virtual bool handleMouseUp(S32 x, S32 y, MASK mask);

	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
	virtual bool handleAcceleratorKey(KEY key, MASK mask);

	// check if we've used these accelerators already
	virtual bool addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp);

	// called to rebuild the draw label
	virtual void buildDrawLabel( void );

	virtual void onCommit( void );

	virtual bool handleKey(KEY key, MASK mask, bool called_from_parent);
	virtual bool handleUnicodeChar(llwchar uni_char, bool called_from_parent);

	// set the hover status (called by it's menu) and if the object is
	// active. This is used for behavior transfer.
	virtual void setHighlight( bool highlight );

	virtual bool handleKeyHere(KEY key, MASK mask);

	virtual bool isActive() const;

	virtual bool isOpen() const;

	LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); }

	virtual void updateBranchParent( LLView* parentp );

	// LLView Functionality
	virtual void onVisibilityChange( bool curVisibilityIn );

	virtual void draw();

	virtual void setEnabledSubMenus(bool enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); }

	virtual void openMenu();

	virtual LLView* getChildView(const std::string& name, bool recurse = true) const;
	virtual LLView* findChildView(const std::string& name, bool recurse = true) const;

private:
	LLHandle<LLView> mBranchHandle;
}; // end class LLMenuItemBranchGL


//-----------------------------------------------------------------------------
// class LLContextMenu
// A context menu
//-----------------------------------------------------------------------------

class LLContextMenu
: public LLMenuGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
	{
		Params()
		{
			changeDefault(visible, false);
		}
	};

protected:
	LLContextMenu(const Params& p);
	friend class LLUICtrlFactory;

public:
	virtual ~LLContextMenu() {}

	// LLView Functionality
	// can't set visibility directly, must call show or hide
	virtual void	setVisible			(bool visible);
	
	virtual void	show				(S32 x, S32 y, LLView* spawning_view = NULL);
	virtual void	hide				();

	virtual bool	handleHover			( S32 x, S32 y, MASK mask );
	virtual bool	handleRightMouseDown( S32 x, S32 y, MASK mask );
	virtual bool	handleRightMouseUp	( S32 x, S32 y, MASK mask );

	virtual bool	addChild			(LLView* view, S32 tab_group = 0);

			LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); }

			LLView*	getSpawningView() const		{ return mSpawningViewHandle.get(); }
			void	setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; }

protected:
	bool						mHoveredAnyItem;
	LLMenuItemGL*				mHoverItem;
	LLRootHandle<LLContextMenu>	mHandle;
	LLHandle<LLView>			mSpawningViewHandle;
};

//-----------------------------------------------------------------------------
// class LLContextMenuBranch
// A branch to another context menu
//-----------------------------------------------------------------------------
class LLContextMenuBranch : public LLMenuItemGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
	{
		Mandatory<LLContextMenu*> branch;
	};

	LLContextMenuBranch(const Params&);

	virtual ~LLContextMenuBranch();

	// called to rebuild the draw label
	virtual void	buildDrawLabel( void );

	// onCommit() - do the primary funcationality of the menu item.
	virtual void	onCommit( void );

	LLContextMenu*	getBranch() { return mBranch.get(); }
	void			setHighlight( bool highlight );

protected:
	void	showSubMenu();

	LLHandle<LLContextMenu> mBranch;
};


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuBarGL
//
// A menu bar displays menus horizontally.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LLMenuBarGL : public LLMenuGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
	{};
	LLMenuBarGL( const Params& p );
	virtual ~LLMenuBarGL();

	/*virtual*/ bool handleAcceleratorKey(KEY key, MASK mask);
	/*virtual*/ bool handleKeyHere(KEY key, MASK mask);
	/*virtual*/ bool handleJumpKey(KEY key);
	/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
	/*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask);

	/*virtual*/ void draw();
	/*virtual*/ bool jumpKeysActive();

	// add a vertical separator to this menu
	virtual bool addSeparator();

	// LLView Functionality
	virtual bool handleHover( S32 x, S32 y, MASK mask );

	// Returns x position of rightmost child, usually Help menu
	S32 getRightmostMenuEdge();

	void resetMenuTrigger() { mAltKeyTrigger = false; }

private:
	// add a menu - this will create a drop down menu.
	virtual bool appendMenu( LLMenuGL* menu );
	// rearrange the child rects so they fit the shape of the menu
	// bar.
	virtual void arrange( void );

	void checkMenuTrigger();

	std::list <LLMenuKeyboardBinding*>	mAccelerators;
	bool						mAltKeyTrigger;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuHolderGL
//
// High level view that serves as parent for all menus
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuHolderGL : public LLPanel
{
public:
	struct Params : public LLInitParam::Block<Params, LLPanel::Params>
	{};
	LLMenuHolderGL(const Params& p);
	virtual ~LLMenuHolderGL() {}

	virtual bool hideMenus();
	void reshape(S32 width, S32 height, bool called_from_parent = true);
	void setCanHide(bool can_hide) { mCanHide = can_hide; }

	// LLView functionality
	virtual void draw();
	virtual bool handleMouseDown( S32 x, S32 y, MASK mask );
	virtual bool handleRightMouseDown( S32 x, S32 y, MASK mask );

	// Close context menus on right mouse up not handled by menus.
	/*virtual*/ bool handleRightMouseUp( S32 x, S32 y, MASK mask );

	virtual bool handleKey(KEY key, MASK mask, bool called_from_parent);
	virtual const LLRect getMenuRect() const { return getLocalRect(); }
	LLView*const getVisibleMenu() const;
	virtual bool hasVisibleMenu() const {return getVisibleMenu() != NULL;}

	static void setActivatedItem(LLMenuItemGL* item);

	// Need to detect if mouse-up after context menu spawn has moved.
	// If not, need to keep the menu up.
	static LLCoordGL sContextMenuSpawnPos;

private:
	static LLHandle<LLView> sItemLastSelectedHandle;
	static LLFrameTimer sItemActivationTimer;

	bool mCanHide;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLTearOffMenu
//
// Floater that hosts a menu
// https://wiki.lindenlab.com/mediawiki/index.php?title=LLTearOffMenu&oldid=81344
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTearOffMenu : public LLFloater
{
public:
	static LLTearOffMenu* create(LLMenuGL* menup);
	virtual ~LLTearOffMenu();

	virtual void draw(void);
	virtual void onFocusReceived();
	virtual void onFocusLost();
	virtual bool handleUnicodeChar(llwchar uni_char, bool called_from_parent);
	virtual bool handleKeyHere(KEY key, MASK mask);
	virtual void translate(S32 x, S32 y);

	void updateSize();

private:
	LLTearOffMenu(LLMenuGL* menup);
	
	void closeTearOff();
	
	LLView*		mOldParent;
	LLMenuGL*	mMenu;
	S32			mTargetHeight;
    bool        mQuitRequested;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemTearOffGL
//
// This class represents a separator.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LLMenuItemTearOffGL : public LLMenuItemGL
{
public:
	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
	{};

	LLMenuItemTearOffGL( const Params& );
	
	virtual void onCommit(void);
	virtual void draw(void);
	virtual U32 getNominalHeight() const;

	LLFloater* getParentFloater();
};


// *TODO: this is currently working, so finish implementation
class LLEditMenuHandlerMgr
{
public:
	LLEditMenuHandlerMgr& getInstance() {
		static LLEditMenuHandlerMgr instance;
		return instance;
	}
	virtual ~LLEditMenuHandlerMgr() {}
private:
	LLEditMenuHandlerMgr() {};
};


// *TODO: Eliminate
// For backwards compatability only; generally just use boost::bind
class view_listener_t : public boost::signals2::trackable
{
public:
	virtual bool handleEvent(const LLSD& userdata) = 0;
	view_listener_t() { sListeners.insert(this); }
	virtual ~view_listener_t() { sListeners.erase(this); }
	
	static void addEnable(view_listener_t* listener, const std::string& name)
	{
		LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
	}
	
	static void addCommit(view_listener_t* listener, const std::string& name)
	{
		LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
	}
	
	static void addMenu(view_listener_t* listener, const std::string& name)
	{
		// For now, add to both click and enable registries
		addEnable(listener, name);
		addCommit(listener, name);
	}

	static void cleanup()
	{
		listener_vector_t listeners(sListeners.begin(), sListeners.end());
		sListeners.clear();

		std::for_each(listeners.begin(), listeners.end(), DeletePointer());
		listeners.clear();
	}

private:
	typedef std::set<view_listener_t*> listener_map_t;
	typedef std::vector<view_listener_t*> listener_vector_t;
	static listener_map_t sListeners;
};

#endif // LL_LLMENUGL_H