/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002-2003 The Inti Development Team.
 *  Copyright (C) 2000 Red Hat, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
//! @file inti/gtk/menushell.h
//! @brief A GtkMenuShell C++ wrapper interface.
//!
//! Provides MenuShell, an abstract base class used to derive the Menu and MenuBar subclasses.

#ifndef INTI_GTK_MENU_SHELL_H
#define INTI_GTK_MENU_SHELL_H

#ifndef INTI_GTK_CONTAINER_H
#include <inti/gtk/container.h>
#endif

#ifndef __GTK_MENU_SHELL_H__
#include <gtk/gtkmenushell.h>
#endif

#ifndef INTI_GTK_MENU_ITEM_H
#include <inti/gtk/menuitem.h>
#endif

namespace Inti {

namespace Gtk {

class MenuShellClass;

//! @enum MenuDirectionType
//! MenuDirectionType represents the directional movements within a menu.

enum MenuDirectionType
{
	MENU_DIR_PARENT = GTK_MENU_DIR_PARENT, //!< To the parent menu shell.
	MENU_DIR_CHILD = GTK_MENU_DIR_CHILD, //!< To the submenu, if any, associated with the item.
	MENU_DIR_NEXT = GTK_MENU_DIR_NEXT, //!< To the next menu item.
	MENU_DIR_PREV = GTK_MENU_DIR_PREV //!< To the previous menu item.
};

//! @class MenuShell menushell.h inti/gtk/menushell.h
//! @brief A GtkMenuShell C++ wrapper class.
//!
//! A MenuShell is the abstract base class used to derive the Menu and MenuBar subclasses.
//! It is a container of MenuItem objects arranged in a list which can be navigated,
//! selected, and activated by the user to perform application functions. A MenuItem can
//! have a submenu associated with it, allowing for nested hierarchical menus.

class MenuShell : public Container
{
	friend class G::Object;
	friend class MenuShellClass;

	MenuShell(const MenuShell&);
	MenuShell& operator=(const MenuShell&);

protected:
//! @name Constructors
//! @{

	MenuShell();
	//!< Construct a new MenuShell.

	explicit MenuShell(GtkMenuShell *menu_shell, bool reference = false);
	//!< Construct a new MenuShell from an existing GtkMenuShell.
	//!< @param menu_shell A pointer to a GtkMenuShell.
	//!< @param reference Set false if the initial reference count is floating, set true if it's not.
	//!<
	//!< <BR>The <EM>menu_shell</EM> can be a newly created GtkMenuShell or an existing
	//!< GtkMenuShell (see G::Object::Object).

//! @}
//  Override these do_ methods when you want to change the default behaviour of the GtkMenuShell.
	
	virtual void do_select_item(GtkWidget *menu_item);
	
	virtual void do_insert(GtkWidget *child, int position);

	virtual int do_get_popup_delay();

//! @name Signal Handlers
//! @{

	virtual void on_deactivate();
	//!< Called when a menu shell is deactivated.

	virtual void on_selection_done();
	//!< Called when a selection has been completed within a menu shell.

//! @}
//  Signals

	typedef G::Signal0<void> DeactivateSignalType;
	typedef G::SignalProxy<TypeInstance, DeactivateSignalType> DeactivateSignalProxy;
	static const DeactivateSignalType deactivate_signal;

	typedef G::Signal0<void> SelectionDoneSignalType;
	typedef G::SignalProxy<TypeInstance, SelectionDoneSignalType> SelectionDoneSignalProxy;
	static const SelectionDoneSignalType selection_done_signal;

public:
//! @name Constructors
//! @{

	virtual ~MenuShell();
	//!< Destructor.
	
//! @}
//! @name Accessors
//! @{

	GtkMenuShell* gtk_menu_shell() const { return (GtkMenuShell*)instance; }
	//!< Get a pointer to the GtkMenuShell structure.

	GtkMenuShellClass* gtk_menu_shell_class() const;
	//!< Get a pointer to the GtkMenuShellClass structure.

	operator GtkMenuShell* () const;
	//!< Conversion operator; safely converts a MenuShell to a GtkMenuShell pointer.

	bool children(std::vector<MenuItem*>& child_list) const;
	//!< Get the list of MenuItem objects contained by this MenuShell.
	//!< @param child_list A reference to a <EM>vector of MenuItem*</EM> to hold the child list.
	//!< @return <EM>true</EM> if the child list is not empty, and <EM>false</EM> if it is empty.

//! @}
//! @name Methods
//! @{

	void append(MenuItem& item, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the end of the menu shell's item list.
	//!< @param item The menu item to add.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.

	void append(MenuItem& item, const AccelKey& accel_key, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the end of the menu shell's item list.
	//!< @param item The menu item to add.
	//!< @param accel_key The accelerator key for the menu item.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.
	//!<
	//!< <BR>Calls Gtk::Menu::get_accel_group() to retrieve the accelerator group for the menu,
	//!< and adds the accelerator key to this accelerator group.

	void append(MenuItem& item, const AccelKey& accel_key, AccelGroup& accel_group, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the end of the menu shell's item list.
	//!< @param item The menu item to add.
	//!< @param accel_key The accelerator key for the menu item.
	//!< @param accel_group The accelerator group to add the accelerator key to.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.

	void append(const char *stock_id, const Slot0<void> *callback);
	//!< Adds a new stock menu item to the end of the menu shell's item list.
	//!< @param stock_id The stock menu item to add.
	//!< @param callback The callback slot to connect to the stock menu item's <EM>activate_signal</EM>.

	void prepend(MenuItem& item, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the beginning of the menu shell's item list.
	//!< @param item The menu item to add.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.

	void prepend(MenuItem& item, const AccelKey& accel_key, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the beginning of the menu shell's item list.
	//!< @param item The menu item to add.
	//!< @param accel_key The accelerator key for the menu item.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.
	//!<
	//!< <BR>Calls Gtk::Menu::get_accel_group() to retrieve the accelerator group for the menu,
	//!< and adds the accelerator key to this accelerator group.

	void prepend(MenuItem& item, const AccelKey& accel_key, AccelGroup& accel_group, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the beginning of the menu shell's item list.
	//!< @param item The menu item to add.
	//!< @param accel_key The accelerator key for the menu item.
	//!< @param accel_group The accelerator group to add the accelerator key to.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.

	void prepend(const char *stock_id, const Slot0<void> *callback);
	//!< Adds a new stock menu item to the beginning of the menu shell's item list.
	//!< @param stock_id The stock menu item to add.
	//!< @param callback The callback slot to connect to the stock menu item's <EM>activate_signal</EM>.

	void insert(MenuItem& item, int position, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the menu shell's item list at the position indicated by position.
	//!< @param item The menu item to add.
	//!< @param position The position in the item list where child is added (numbered from 0 to n-1).
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.

	void insert(MenuItem& item, int position, const AccelKey& accel_key, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the menu shell's item list at the position indicated by position.
	//!< @param item The menu item to add.
	//!< @param position The position in the item list where child is added (numbered from 0 to n-1).
	//!< @param accel_key The accelerator key for the menu item.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.
	//!<
	//!< <BR>Calls Gtk::Menu::get_accel_group() to retrieve the accelerator group for the menu,
	//!< and adds the accelerator key to this accelerator group.

	void insert(MenuItem& item, int position, const AccelKey& accel_key, AccelGroup& accel_group, const Slot0<void> *callback = 0);
	//!< Adds a new menu item to the menu shell's item list at the position indicated by position.
	//!< @param item The menu item to add.
	//!< @param position The position in the item list where child is added (numbered from 0 to n-1).
	//!< @param accel_key The accelerator key for the menu item.
	//!< @param accel_group The accelerator group to add the accelerator key to.
	//!< @param callback The callback slot to connect to item's <EM>activate_signal</EM>.

	void insert(const char *stock_id, int position, const Slot0<void> *callback);
	//!< Adds a new stock menu item to the menu shell's item list at the position indicated by position.
	//!< @param stock_id The stock menu item to add.
	//!< @param position The position in the item list where child is added (numbered from 0 to n-1).
	//!< @param callback The callback slot to connect to the stock menu item's <EM>activate_signal</EM>.

	void select_item(MenuItem& item);
	//!< Selects the menu item from the menu shell.
	//!< @param item The MenuItem to select.

	void deselect();
	//!< Deselects the currently selected item from the menu shell, if any.

	void activate_item(MenuItem& item, bool force_deactivate);
	//!< Activates the menu item within the menu shell.
	//!< @param item The menu item to activate.
	//!< @param force_deactivate If <EM>true</EM>, force the deactivation of the menu shell
	//!<                         after the menu item is activated.
	
	void deactivate();
	//!< Deactivates the menu shell. Typically this results in the menu shell being erased
	//!< from the screen.

	void select_first(bool search_sensitive);
	//!< Select the first visible or selectable child of the menu shell; don't select tearoff
	//!< items unless the only item is a tearoff item.
	//!< @param search_sensitive If <EM>true</EM>, search for the first selectable menu item,
	//!< otherwise select nothing if the first item isn't sensitive. 
	//!<
	//!< <BR><EM>search_sensitive</EM> should be false if the menu is being popped up initially.

//! @}
//! @name Signal Proxies
//! @{

	const DeactivateSignalProxy sig_deactivate()
	{
		return DeactivateSignalProxy(this, &deactivate_signal);
	}
	//!< Connect to the deactivate_signal; emitted when a menu shell is deactivated.

	const SelectionDoneSignalProxy sig_selection_done()
	{
		return SelectionDoneSignalProxy(this, &selection_done_signal);
	}
	//!< Connect to the selection_done_signal; emitted when a selection has been completed
	//!< within a menu shell.

//! @}
};

} // namespace Gtk

} // namespace Inti

#endif // INTI_GTK_MENU_SHELL_H

