#ifndef MENU_H
#include "mouse.h"
#ifndef STD_H
# include "std.h"
#endif
#ifdef __cplusplus
# include <Objection.h>
# include <String.h>
# ifndef Listdeclare
#  include <List.h>
# endif
#endif

#define ID_ERROR (-2)
#define ID_NOCLICK	0	/* Idnum returned if no mouse click since last call */
#define ID_ANYITEM	(-1)
/* Struct button stores data returned from selectbutton().    */
struct button_s {
	int idnum;				/* Menu item # selected     */
	enum whichbutton button;				/* Button pressed <L or R>  */
# ifdef __cplusplus
	private:
	static int next_id;
	static BITS b_used;
	int get_next_id(enum whichbutton x);
	public:
	button_s();
	button_s(int id, enum whichbutton b=AnyB)
		{idnum = id; button = b;}
	button_s(enum whichbutton b);
	button_s operator|(C button_s& x) C;
	int operator-(C button_s& x) C;
	button_s operator+(int x) C;
	BOOL operator==(C button_s& x) C;
	operator int() C;
	BOOL clicked() C {return idnum!=ID_NOCLICK;}
	static Objection error;
# endif
	};

/******************************** Struct Item *******************************/
/* Tells where to make pop_up menu.  See element popdir.*/
/* Default is POP_RIGHT.  May be ored together.*/
#define POP_DOWN	01
#define POP_RIGHT	02


enum dtype	{None, Int, Double, Float, C_String, Char, Long, Short, StrArray,
				CPP_String, Pot, DPot, Unknown};

typedef struct	{
	TBOOL nohide;			/* Is item visible on screen?	    */
	TBOOL actG;			/* Is this menu active?		    */
	struct item *parent;	/* for pop-up menus only */
	struct item *first;		/* first item in this menu */
	struct item *moused;	/* which one was the mouse on last? */
	int xi, yi, width;
	int foregnd, backgnd;		/* Foreground & background colors: 
						default			    */
	int fifmouse, bifmouse;		/* Fgnd & bckgnd colors if moused   */
	int fnotactive, bnotactive;	/* Fgnd & bckgnd colors if inactive */
	TBITS popdir;		/* where to put popup menu (SEE POP_*) */
#ifdef __cplusplus
	C static BOOL false;	// for unclickable items
#endif
	} MENU;


struct format_s {char *printfmt, *readfmt; enum dtype d_type;
				int q_print;};

struct item {
	/* private: */
	TBOOL Xactive;			/* Is item active?		    */
	PT qpos;			/* Where to put cursor for queries  */
	int xi, yi, xf, yf;			/* Upper left, lower right corners
								of menu	item		    */
	void *underneath;	/* whatever used to be underneath the menu item */
	struct item *next;	/* next item in the menu */
	MENU *base;				/* which menu is this a part of ? */
	/* public below: */
             		/* Struct item stores many kinds of data which
				   refer to each individual menu item.  A
				   pointer to a item structure can also be
				   used as a pointer to an entire menu.	    */


	struct format_s format;
	int foregnd, backgnd;		/* Foreground & background colors: 
						default			    */
	int fifmouse, bifmouse;		/* Fgnd & bckgnd colors if moused   */
	int fnotactive, bnotactive;	/* Fgnd & bckgnd colors if inactive */
	int id;				/* ID number for menu item	    */
	C BOOL *active;		/* Where to look to determine if item is active */
	TBOOL free_fmt;		/* should the format string be freed by menufree? */
	TBOOL query;			/* Does item accept user input?	    */
	C char *C*Strarray;		/* Stores arrays for strquery	    */
	void * value;		/* Stores pointer to data	    */
#ifdef __cplusplus
	int width() C {return xf-xi;}
#endif
	};

/* module MENU */
#if defined(__cplusplus)
#if 0
BOOL additem(MENU *menu, C void *data, C char *format,
				C BOOL *active= &MENU::false, int id = ID_NOCLICK);
BOOL addquery(MENU *menu, void *data, char *format, C BOOL *active,
						int id);
BOOL addstrarray(MENU *menu, void *data, char *format, C BOOL *active,
					C char *C*selections, int id = ID_NOCLICK);
BOOL addstrquery(MENU *menu, void *data, char *format, C BOOL *active,
					C char *C*selections, int id);
#endif
#else
# if defined(__STDC__)
BOOL additem(MENU *menu, C void *data, C char *format, C BOOL *active,
						int id);
BOOL addquery(MENU *menu, void *data, char *format, C BOOL *active,
						int id);
BOOL addstrarray(MENU *menu, void *data, char *format, C BOOL *active,
					C char *C*selections, int id);
BOOL addstrquery(MENU *menu, void *data, char *format, C BOOL *active,
					C char *C*selections, int id);
# endif
#endif
#if defined(__STDC__) || defined(__cplusplus)
void changeactive(MENU *menu);
MENU *makemenu(int x, int y, int width, int fg, int bg, int fgm,
								int bgm, int fgna, int bgna);
MENU *makepopup(struct item *menuitem, int width);
struct item *finditem(MENU * menu, int id);
void refresh(MENU *menu);
void refresh_all(MENU *menu);
BOOL showid(MENU *menu, int id_to_show);
struct button_s selectbutton(MENU *menu);
int itemcount(C MENU *menu);
void menufree(MENU *menu);
BOOL itemmove(struct item *menuitem, int x, int y);
BOOL showvar(MENU *m, void *q);
# ifdef __cplusplus
void popup(MENU *menu, BOOL show_noshow = TRUE);
# else
void popup(MENU *menu, BOOL show_noshow);
# endif

/* DO NOT USE THE x... functions! (Except at your own risk). */
BOOL xadditem(MENU *menu, C void *data, C char *format, C BOOL *active,
						int id, enum dtype dtype);
BOOL xaddquery(MENU *menu, void *data, C char *format, C BOOL *active,
						int id, enum dtype dtype);
BOOL xaddstrarray(MENU *menu, C unsigned *data, C char *format, C BOOL *active,
					C char *C*selections, int id, enum dtype dtype);
BOOL xaddstrquery(MENU *menu, unsigned *data, C char *format, C BOOL *active,
					C char *C*selections, int id, enum dtype dtype);
#else
BOOL additem();
BOOL addquery();
BOOL addstrarray();
BOOL addstrquery();
void changeactive();
MENU *makemenu();
MENU *makepopup();
struct item *finditem();
void popup();
void refresh();
void refresh_all();
BOOL showid();
struct button_s selectbutton();
int itemcount();
void menufree();
BOOL itemmove();
BOOL showvar();

/* DO NOT USE THE x... functions! (Except at your own risk). */
BOOL xadditem();
BOOL xaddquery();
BOOL xaddstrarray();
BOOL xaddstrquery();
#endif

#if !defined(__cplusplus) && !defined(c_plusplus)
/* below is messiness  to allow extra c++ features */
# define additem(m,d,f,a,i)	xadditem(m,d,f,a,i,Unknown)
# define addquery(m,d,f,a,i)	xaddquery(m,d,f,a,i,Unknown)
# define addstrarray(m,d,f,a,s,i) xaddstrarray(m,(C unsigned *)d,f,a,s,i,Unknown)
# define addstrquery(m,d,f,a,s,i) xaddstrquery(m,(unsigned *)d,f,a,s,i,Unknown)
#else
/* These inline function calls allow strict type checking of menu items. */
/* A type mismatch yields a runtime abort. */
inline BOOL additem(MENU *menu, C void *data, C char *format,
					C BOOL *active = &MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, None);}
inline BOOL additem(MENU *menu, C int *data, C char *format,
						C BOOL *active = &MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, Int);}
inline BOOL addquery(MENU *menu, int *data, C char *format, C BOOL *active,
						int id)
		{return xaddquery(menu, data, format, active, id, Int);}
inline BOOL additem(MENU *menu, C double *data, C char *format,
					C BOOL *active=&MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, Double);}
inline BOOL addquery(MENU *menu, double *data, C char *format, C BOOL *active,
						int id)
		{return xaddquery(menu, data, format, active, id, Double);}
inline BOOL additem(MENU *menu, C short *data, C char *format,
					C BOOL *active=&MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, Short);}
inline BOOL addquery(MENU *menu, short *data, C char *format, C BOOL *active,
						int id)
		{return xaddquery(menu, data, format, active, id, Short);}
inline BOOL additem(MENU *menu, C long *data, C char *format,
					C BOOL *active=&MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, Long);}
inline BOOL addquery(MENU *menu, long *data, C char *format, C BOOL *active,
						int id)
		{return xaddquery(menu, data, format, active, id, Long);}
inline BOOL additem(MENU *menu, C float *data, C char *format,
					C BOOL *active=&MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, Float);}
inline BOOL addquery(MENU *menu, float *data, C char *format, C BOOL *active,
						int id)
		{return xaddquery(menu, data, format, active, id, Float);}
inline BOOL additem(MENU *menu, C char *data, C char *format,
					C BOOL *active=&MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, C_String);}
inline BOOL addquery(MENU *menu, char *data, C char *format, C BOOL *active,
						int id)
		{return xaddquery(menu, data, format, active, id, C_String);}

inline BOOL additem(MENU *menu, C String *data, C char *format,
					C BOOL *active=&MENU::false, int id=ID_NOCLICK)
		{return xadditem(menu, data, format, active, id, CPP_String);}
inline BOOL addquery(MENU *menu, String *data, C char *format, C BOOL *active,
						int id)
		{return xaddquery(menu, data, format, active, id, CPP_String);}

#ifndef LISTDECLARE_STRING
# define LISTDECLARE_STRING
Listdeclare(String)
#endif

BOOL addstrarray(MENU *menu, C unsigned *data, C char *format,
				C BOOL *active, /*C*/ List(String)& selections,
				int id=ID_NOCLICK);
BOOL addstrquery(MENU *menu, unsigned *data, C char *format,
				C BOOL *active, /*C*/ List(String)& selections, int id);
inline BOOL addstrarray(MENU *menu, C int *data, C char *format,
						C BOOL *active, /*C*/ List(String)& selections,
						int id=ID_NOCLICK)
	{return addstrarray(menu, (C unsigned *)data, format, active,
					selections, id);}

inline BOOL addstrquery(MENU *menu, int *data, C char *format,
				C BOOL *active, /*C*/ List(String)& selections, int id)
		{return addstrquery(menu, (unsigned *)data, format, active,
					selections, id);}

inline BOOL addstrarray(MENU *menu, C unsigned *data, C char *format,
						C BOOL *active, C char *C*selections, int id=ID_NOCLICK)
	{return xaddstrarray(menu, data, format, active, selections, id, C_String);}

inline BOOL addstrquery(MENU *menu, unsigned *data, C char *format,
				C BOOL *active, C char *C*selections, int id)
		{return xaddstrquery(menu, data, format, active,
					selections, id, C_String);}

inline BOOL addstrarray(MENU *menu, C int *data, C char *format,
						C BOOL *active, C char *C*selections,
						int id=ID_NOCLICK)
	{return xaddstrarray(menu, (C unsigned *)data, format, active,
					selections, id, C_String);}

inline BOOL addstrquery(MENU *menu, int *data, C char *format,
				C BOOL *active, C char *C*selections, int id)
		{return xaddstrquery(menu, (unsigned *)data, format, active,
					selections, id, C_String);}
# endif

# ifdef __cplusplus

class Menu	{
	MENU *menu;
	Menu(C Menu& x);	// no copy-initializer
	public:
	Menu()	{menu=0;}
	Menu(int x, int y, int width, int fg, int bg, int fgm,
								int bgm, int fgna, int bgna);
	Menu(struct item *menuitem, int width);
	~Menu()	{menufree(menu);}
	C Menu& operator=(C Menu& x);
	operator MENU *();
	static Objection no_mem;
	static Objection bad_arg;
	struct item *operator[](C struct button_s &id);
	struct item *operator[](C void * x);	// find item with specified data.
	struct button_s selectbutton() {return ::selectbutton(menu);}
	void popup(BOOL show_noshow=TRUE)	{::popup(menu, show_noshow);}
	BOOL showvar(void *q) {return ::showvar(menu, q);}
	int width() C	{return menu?menu->width:0;}
	};




struct item *
Menu::operator[](C struct button_s& id)
{
 return finditem(menu, id.idnum);
}
# endif
#define MENU_H	1
#endif /* MENU_H */
