/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 *  Authors: Michel Zucchi <notzed@ximian.com>
 *
 *  Copyright 2003 Ximian, Inc. (www.ximian.com)
 *
 *  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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef __E_POPUP_H__
#define __E_POPUP_H__

#include <glib-object.h>
#include "libedataserver/e-msgport.h"

#ifdef __cplusplus
extern "C" {
#pragma }
#endif /* __cplusplus */

/* This is an abstract popup menu management/merging class.

   To implement your own popup menu system, just create your own
   target types and implement the target free method. */

typedef struct _EPopup EPopup;
typedef struct _EPopupClass EPopupClass;

typedef struct _EPopupItem EPopupItem;
typedef struct _EPopupFactory EPopupFactory; /* anonymous type */
typedef struct _EPopupTarget EPopupTarget;

typedef void (*EPopupActivateFunc)(EPopup *ep, EPopupItem *item, void *data);
typedef void (*EPopupFactoryFunc)(EPopup *emp, void *data);
typedef void (*EPopupItemsFunc)(EPopup *ep, GSList *items, void *data);

/**
 * enum _e_popup_t - Popup item type enumeration.
 * @E_POPUP_ITEM: A simple menu item.
 * @E_POPUP_TOGGLE: A toggle menu item. If struct _EPopupItem::image is
 * not NULL, then it points to GtkImage directly and there is a toggle
 * with an image and caption shown in the popup menu.
 * @E_POPUP_RADIO: A radio menu item.  Note that the radio group is
 * global for the entire (sub) menu.  i.e. submenu's must be used to
 * separate radio button menu items.
 * @E_POPUP_IMAGE: A &GtkImage menu item.  In this case the @image
 * field of &struct _EPopupItem points to the &GtkImage directly.
 * @E_POPUP_SUBMENU: A sub-menu header.  It is up to the application
 * to define the @path properly so that the submenu comes before the
 * submenu items.
 * @E_POPUP_BAR: A menu separator bar.
 * @E_POPUP_TYPE_MASK: Mask used to separate item type from option bits.
 * @E_POPUP_ACTIVE: An option bit to signify that the radio button or
 * toggle button is active.
 * @E_POPUP_INCONSISTENT: An option to toggle only, if set, the toggle
 * is shown in inconsistent state. This is used before E_POPUP_ACTIVE.
 */
enum _e_popup_t {
	E_POPUP_ITEM = 0,
	E_POPUP_TOGGLE,
	E_POPUP_RADIO,
	E_POPUP_IMAGE,
	E_POPUP_SUBMENU,
	E_POPUP_BAR,
	E_POPUP_TYPE_MASK = 0xffff,
	E_POPUP_ACTIVE = 0x10000,
	E_POPUP_INCONSISTENT = 0x20000
};

/* FIXME: activate passes back no context data apart from that provided.
   FIXME: It should pass the target at the least.  The menu widget is
   useless */

/**
 * struct _EPopupItem - A popup menu item definition.
 * @type: The type of the popup.  See the &enum _epopup_t definition
 * for possible values.
 * @path: An absolute path, which when sorted using a simple ASCII
 * sort, will put the menu item in the right place in the menu
 * heirarchy.  '/' is used to separate menus from submenu items.
 * @label: The text of the menyu item.
 * @activate: A function conforming to &EPopupActivateFunc which will
 * be called when the menu item is activated.
 * @user_data: Extra per-item user-data available to the
 * application.  This is not passed to the @data field of @activate.
 * @image: For most types, the name of the icon in the icon theme to
 * display next to the menu item, if required.  For the %E_POPUP_IMAGE
 * type, it is a pointer to the &GtkWidget instead.
 * @visible: Visibility mask.  Used together with the &EPopupTarget mask
 * to determine if the item should be part of the menu or not.
 * @enable: Sensitivity mask. Similar to the visibility mask, but
 * currently unimplemented.
 * @popup: Used by e-popup to reference the parent object from
 * callbacks.
 *
 * The EPopupItem defines a single popup menu item, or submenu item,
 * or menu separator based on the @type.  Any number of these are
 * merged at popup display type to form the popup menu.
 *
 * The application may extend this structure using simple C structure
 * containers to add any additional fields it may require.
 */
struct _EPopupItem {
	enum _e_popup_t type;
	char *path;		/* absolute path! must sort ascii-lexographically into the right spot */
	char *label;
	EPopupActivateFunc activate;
	void *user_data;	/* user data, not passed directly to @activate */
	void *image;		/* char* for item type, GtkWidget * for image type */
	guint32 visible;	/* visibility mask */
	guint32 enable;		/* sensitivity mask */
};

/**
 * struct EPopupTarget - A popup menu target definition.
 *
 * @popup: The parent popup object, used for virtual methods on the target.
 * @widget: The parent widget, where available.  In some cases the
 * type of this object is part of the published api for the target.
 * @type: The target type.  This will be defined by the
 * implementation.
 * @mask: Target mask. This is used to sensitise and show items
 * based on their definition in EPopupItem.
 *
 * An EPopupTarget defines the context for a specific popup menu
 * instance.  The root target object is abstract, and it is up to
 * sub-classes of &EPopup to define the additional fields required to
 * make it usable.
 */
struct _EPopupTarget {
	struct _EPopup *popup;	/* used for virtual methods */

	struct _GtkWidget *widget;	/* used if you need a parent toplevel, if available */
	guint32 type;		/* targe type, for implementors */

	guint32 mask;		/* depends on type, visibility mask */

	/* implementation fields follow */
};

/**
 * struct _EPopup - A Popup menu manager.
 *
 * @object: Superclass, GObject.
 * @priv: Private data.
 * @menuid: The id of this menu instance.
 * @target: The current target during the display of the popup menu.
 *
 * The EPopup manager object.  Each popup menu is built using this
 * one-off object which is created each time the popup is invoked.
 */
struct _EPopup {
	GObject object;

	struct _EPopupPrivate *priv;

	char *menuid;

	EPopupTarget *target;
};

/**
 * struct _EPopupClass -
 *
 * @object_class: Superclass type.
 * @factories: A list of factories for this particular class of popup
 * menu.
 * @target_free: Virtual method to free the popup target.  The base
 * class frees the allocation and unrefs the popup pointer
 * structure.
 *
 * The EPopup class definition.  This should be sub-classed for each
 * component that wants to provide hookable popup menus.  The
 * sub-class only needs to know how to allocate and free the various target
 * types it supports.
 */
struct _EPopupClass {
	GObjectClass object_class;

	EDList factories;

	void (*target_free)(EPopup *ep, EPopupTarget *t);
};

GType e_popup_get_type(void);

EPopup *e_popup_new(const char *menuid);

/* Static class methods */
EPopupFactory *e_popup_class_add_factory(EPopupClass *klass, const char *menuid, EPopupFactoryFunc func, void *data);
void e_popup_class_remove_factory(EPopupClass *klass, EPopupFactory *f);

EPopup *e_popup_construct(EPopup *, const char *menuid);

void e_popup_add_items(EPopup *, GSList *items, const char *domain, EPopupItemsFunc freefunc, void *data);

void e_popup_add_static_items(EPopup *emp, EPopupTarget *target);
/* do not call e_popup_create_menu, it can leak structures if not used right */
struct _GtkMenu *e_popup_create_menu(EPopup *, EPopupTarget *, guint32 mask);
struct _GtkMenu *e_popup_create_menu_once(EPopup *emp, EPopupTarget *, guint32 mask);

void *e_popup_target_new(EPopup *, int type, size_t size);
void e_popup_target_free(EPopup *, void *);

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

/* popup plugin target, they are closely integrated */

/* To implement a basic popup menu plugin, you just need to subclass
   this and initialise the class target type tables */

#include "e-util/e-plugin.h"

typedef struct _EPopupHookMenu EPopupHookMenu;
typedef struct _EPopupHook EPopupHook;
typedef struct _EPopupHookClass EPopupHookClass;

typedef struct _EPluginHookTargetMap EPopupHookTargetMap;
typedef struct _EPluginHookTargetKey EPopupHookTargetMask;

typedef void (*EPopupHookFunc)(struct _EPlugin *plugin, EPopupTarget *target);

/**
 * struct _EPopupHookMenu -
 *
 * @hook: Parent pointer.
 * @id: The identifier of the menu to which these items belong.
 * @target_type: The target number of the type of target these menu
 * items expect. It will generally also be defined by the menu id.
 * @items: A list of EPopupItems.
 * @factory: If supplied, a function to call
 *
 * The structure used to keep track of all of the items that a plugin
 * wishes to add to a given menu. This is used internally by a factory
 * method set on EPlugin to add the right menu items to a given menu.
 */
struct _EPopupHookMenu {
	struct _EPopupHook *hook; /* parent pointer */
	char *id;		/* target menu id for these menu items */
	int target_type;	/* target type of this menu */
	GSList *items;		/* items to add to menu */
	char *factory;		/* optional factory to call for adding menu items */
};

/**
 * struct _EPopupHook - A popup menu hook.
 *
 * @hook: Superclass.
 * @menus: A list of EPopupHookMenus, for all menus registered on
 * this hook type.
 *
 * The EPopupHook class loads and manages the meta-data required to
 * map plugin definitions to physical menus.
 */
struct _EPopupHook {
	EPluginHook hook;

	GSList *menus;
};

/**
 * struct _EPopupHookClass -
 *
 * @hook_class: Superclass.
 * @target_map: Table of EPluginHookTargetMaps which enumerate the
 * target types and enable bits of the implementing class.
 * @popup_class: The EPopupClass of the corresponding popup manager
 * for the implementing class.
 *
 * The EPopupHookClass is a concrete class, however it is empty on its
 * own.  It needs to be sub-classed and initialised appropriately.
 *
 * The EPluginHookClass.id must be set to the name and version of the
 * hook handler itself.  The @target_map must be initialised with the
 * data required to enumerate the target types and enable flags
 * supported by the implementing class.
 */
struct _EPopupHookClass {
	EPluginHookClass hook_class;

	/* EPopupHookTargetMap by .type */
	GHashTable *target_map;
	/* the popup class these popups belong to */
	EPopupClass *popup_class;
};

GType e_popup_hook_get_type(void);

/* for implementors */
void e_popup_hook_class_add_target_map(EPopupHookClass *klass, const EPopupHookTargetMap *);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __E_POPUP_H__ */
