/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

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



#ifndef ___V_MENU_H___
#define ___V_MENU_H___

#include "v/v_types.h"

class VWindow;

// ----- VMenuItem type ------
#define VMT_OTHER		0
#define VMT_APPLICATION	1
#define VMT_FILE			2
#define VMT_EDIT			3
#define VMT_VIEW			4
#define VMT_WINDOW		5
#define VMT_HELP			6

#define VMT_APP_START	101
#define VMT_SETUP		101
#define VMT_ABOUT		102
#define VMT_CLOSE		103
#define VMT_QUIT			104
#define VMT_APP_END	104


#define VMF_UNDO	0x00000001
#define VMF_REDO	0x00000002
#define VMF_CUT		0x00000004
#define VMF_COPY	0x00000008
#define VMF_PASTE	0x00000010
#define VMF_CLEAR	0x00000020
#define VMF_SEL_ALL	0x00000040

#define VMT_EDIT_START	200
#define VMT_UNDO		(VMT_EDIT_START+VMF_UNDO)
#define VMT_REDO		(VMT_EDIT_START+VMF_REDO)
#define VMT_CUT			(VMT_EDIT_START+VMF_CUT)
#define VMT_COPY		(VMT_EDIT_START+VMF_COPY)
#define VMT_PASTE		(VMT_EDIT_START+VMF_PASTE)
#define VMT_CLEAR		(VMT_EDIT_START+VMF_CLEAR)
#define VMT_SEL_ALL		(VMT_EDIT_START+VMF_SEL_ALL)
#define VMT_EDIT_END	VMT_SEL_ALL

#define VMT_SEPARATOR	-1

// ------ VMenuItem flag ------
#define VMF_STATE_MASK	0x0007	// menu status
#define VMF_ENABLED		0x0001	// can be choosed
#define VMF_CHECKED		0x0002	// check mark
#define VMF_FLAGGED		0x0004	// diamond mark

#define VMF_BEHAVIOR_MASK	0x3000	// action when window go background for Mac
#define VMF_B_AUTOMATIC		0x0000	// automatically disable the menu which should be done
#define VMF_B_DISABLE		0x1000	// disable the menu
#define VMF_B_HIDE			0x2000	// hide the menu
#define VMF_MERGED			0x4000	// marged item

class VMenuBar;
class VCustomizedMenuBar;

class VMenuItem {
  public:
	VMenuItem(
		short type,
		short flag,
		char *name,
		LC_WRITING_STYLE *ws,
		short modifier,
		char shortcut_key,
		char access_key,
		V_CALLBACK(func));	// machine dependent constructor (to allocate id)
	~VMenuItem();
	
	void	set_submenu(VMenuItem *menu);
	void	append(VMenuItem *menu, int where = 0/*last*/);
	void	append_to_list(VMenuItem *menu);
	void	merge(VMenuItem *from);
	void	remove(VMenuItem *menu);
	static void	remove_from_list(VMenuItem *menu, VMenuItem **from_list);
	
	int		get_id()	{ return id; }
	VMenuBar *	get_bar()	{ return menu_bar; }
	
	void	debug_print(int indent);
	static int	get_count() { return cnt; }
	
  protected:
	VMenuItem(VMenuItem& item);	// single item copy
	VMenuItem(VMenuItem& item, VMenuBar *menu_bar); // hierarchic copy

	void	set_member_vars(
		int id, short type, short flag,
		char *name, LC_WRITING_STYLE *ws,
		short modifier, char shortcut_key, char access_key,
		V_CALLBACK(func), VMenuBar *menu_bar);	// machine independent constructor
	
	int				id;
	short			type;
	short			flag;
	
	L_CHAR *		name;
	LC_WRITING_STYLE *	ws;
	
	short			modifier;
	char			shortcut_key;
	char			access_key;

	V_CALLBACK		(func);

	VMenuItem *		submenu;
	VMenuItem *		next;
	
	VMenuBar *		menu_bar;
	VMenuItemInfo	info;
	
	static int		cnt;
	
	friend class VMenuBar;
	friend class VCustomizedMenuBar;
	friend class VCustomizedMenuBarImp;	// machine dependent routine
	friend class VMenuItemHash;
};

const int v_menu_item_hash_size = 128;
struct VMenuList {
	VMenuItem	*item;
	VMenuList	*next;
};
typedef VMenuList* VMenuHashNode;
class VMenuItemHash {
  public:
	VMenuItemHash(VMenuBar *bar);
	~VMenuItemHash();
	VMenuItem *	search(int id) const;
  protected:
	void add_menu_items(VMenuItem *menu);
	
	VMenuHashNode hash[v_menu_item_hash_size];
};


class VMenuBar
{
  public:

	VMenuBar(VMenuItem *items, int category, bool base);
	virtual ~VMenuBar();
	
	VMenuItem *			get_items() { return items; }
	bool				is_base() { return base; }
	int					get_category() { return category; }
	
	static VMenuBar *	get_menu_bar(int category);
	
	static int			edit_id_2_item_type(int id);
	
  protected:
	VMenuBar() {}	// subclass may initialize all member
	static void			init();	// called as menu for category 0 is created 
	static VMenuBar *	v_menu_bars;
	VMenuBar *		next;
	
	VMenuItem *		items;

	int			category;
	bool		base;
	
  private:
	VMenuBar(VMenuBar&);	// no copy
};


class VCustomizedMenuBar : public VMenuBar {
  public:
	static VCustomizedMenuBar *	create(int category, VWindow *window);
	virtual ~VCustomizedMenuBar() { delete hash; }
	
	VMenuItem *	search(int id) const { return hash->search(id); }
	
	void	update(VMenuItem *menus=0);	// called from OS etc. when update is needed
	
	bool	set_menu_func(int id, V_CALLBACK(func));

	bool	get_menu_name(int id, const L_CHAR **name);
	bool	set_menu_name(int id, const L_CHAR *name);

	bool	get_menu_flag(int id, short *flag);
	bool	set_menu_flag(int id, short flag);

	bool	menu_choosed(VMenuItem *item);
	bool	menu_choosed(int id) { return menu_choosed(search(id)); }
	
	VWindow *	get_window() { return window; }
	
  protected:
	VCustomizedMenuBar(VMenuBar *bar, VWindow *window);

	static void	add_flag_hierarchic(VMenuItem *items, short flag);
	
	// machine dependent routines
	
	void	make_customized_menu(VMenuBar *bar);	// make machine dependent menu
	
	static void	set_menu_flag_do(VMenuItem *item, short flag);	// machine dependent
	static void	set_menu_name_do(VMenuItem *item, const L_CHAR *name);	// machine dependent
	bool	menu_choosed_do(VMenuItem *item);
	
	VWindow *	window;
	VMenuItemHash *	hash;
	
	friend class VCustomizedMenuBarImp;	// machine dependent routines
};

#include "machine/v_menu_m.h"

#endif
