//
// PMenu.hh for pekwm
// Copyright (C) 2004 Claes Nasten <pekdon{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#include "../config.h"

#ifndef _PMENU_HH_
#define _PMENU_HH_

#include "pekwm.hh"

#include <list>
#include <map>
#include <string>

class PDecor;
class PDecor::TitleItem;
class PTexture;
class ActionEvent;
class Theme;

class PMenu : public PDecor {
public:
	class Item {
	public:
		enum Type {
			MENU_ITEM_NORMAL, MENU_ITEM_SEPARATOR, MENU_ITEM_HIDDEN
		};
		Item(const std::string &name, PWinObj *wo_ref = NULL) :
			_x(0), _y(0), _name(name), _wo_ref(wo_ref), _type(MENU_ITEM_NORMAL) { }

		virtual ~Item(void) { }

		inline int getX(void) const { return _x; }
		inline int getY(void) const { return _y; }
		inline const std::string &getName(void) const { return _name; }
		inline const ActionEvent &getAE(void) const { return _ae; }
		inline PWinObj *getWORef(void) const { return _wo_ref; }
		inline PMenu::Item::Type getType(void) const { return _type; }

		inline void setX(int x) { _x = x; }
		inline void setY(int y) { _y = y; }
		inline void setName(const std::string &name) { _name = name; }
		inline void setAE(const ActionEvent &ae) { _ae = ae; }
		inline void setWORef(PWinObj *wo_ref) { _wo_ref = wo_ref; }
		inline void setType(PMenu::Item::Type type) { _type = type; }

	private:
		int _x, _y;
		std::string _name;

		ActionEvent _ae; // used for specifying action of the entry
		PWinObj *_wo_ref; // used for client, frame, parent etc

		PMenu::Item::Type _type; // normal, separator or hidden item
	};

	PMenu(Display *dpy, Theme *theme, const std::string &title, const std::string decor_name = "MENU");
	virtual ~PMenu(void);

	// START - PWinObj interface.
	virtual void unmapWindow(void);

	virtual void setFocused(bool focused);

	virtual ActionEvent *handleButtonPress(XButtonEvent *ev);
	virtual ActionEvent *handleButtonRelease(XButtonEvent *ev);
	virtual ActionEvent *handleMotionEvent(XMotionEvent *ev);
	virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev);
	virtual ActionEvent *handleLeaveEvent(XCrossingEvent *ev);
	// END - PWinObj interface.

	static inline PMenu *findMenu(Window win) {
		std::map<Window, PMenu*>::iterator it = _menu_map.find(win);
		if (it != _menu_map.end())
			return it->second;
		return NULL;
	}

	inline PMenu::Item *getItemCurr(void) { return *_item_curr; }
	void selectNextItem(void);
	void selectPrevItem(void);

	// modifying menu content
	void setTitle(const std::string &title);

	virtual void insert(PMenu::Item *item);
	virtual void insert(const std::string &name, PWinObj *wo_ref = NULL);
	virtual void insert(const std::string &name, const ActionEvent &ae,
											PWinObj *wo_ref = NULL);
	virtual void remove(PMenu::Item *item);
	virtual void removeAll(void);

	virtual void reload(void) { }
	void buildMenu(void);

	inline uint size(void) const { return _item_list.size(); }
	inline std::list<PMenu::Item*>::iterator m_begin(void) { return _item_list.begin(); }
	inline std::list<PMenu::Item*>::iterator m_end(void) { return _item_list.end(); }

	inline MenuType getMenuType(void) const { return _menu_type; }

	virtual void handleItemExec(PMenu::Item *item) { }

	// control ( mapping, unmapping etc )
	void mapUnderMouse(void);
	void mapSubmenu(PMenu *menu, bool focus = false);
	void unmapSubmenus(void);
	void unmapAll(void);
	void gotoParentMenu(void);

	void select(PMenu::Item *item, bool unmap_submenu = true);
	void selectItem(std::list<PMenu::Item*>::iterator item, bool unmap_submenu = true);
	void deselectItem(bool unmap_submenu = true);
	void selectItemNum(uint num);
	void selectItemRel(int off);
	void exec(PMenu::Item *item);

protected:
	void checkItemWORef(PMenu::Item *item);

private:
	void handleItemEvent(MouseEventType type, int x, int y);

	void buildMenuCalculate(void);
	void buildMenuPlace(void);
	void buildMenuRender(void);
	void buildMenuRenderState(Pixmap &pix, ObjectState state);
	void buildMenuRenderItem(Pixmap pix, ObjectState state, PMenu::Item *item);

	PMenu::Item *findItem(int x, int y);
	void makeInsideScreen(int x, int y);

protected:
	MenuType _menu_type;

	// menu content data
	std::list<PMenu::Item*> _item_list;
	std::list<PMenu::Item*>::iterator _item_curr;

private:
	static std::map<Window, PMenu*> _menu_map;

	PWinObj *_menu_wo;
	PMenu *_menu_parent;
	PDecor::TitleItem _title;

	// menu render data
	Pixmap _menu_bg_fo, _menu_bg_un, _menu_bg_se;

	// menu disp data
	uint _item_height, _item_width_max, _item_width_max_avail;
  uint _separator_height;

	uint _size; // size, hidden items excluded
	uint _rows, _cols;
	bool _scroll;
  bool _has_submenu;
};

#endif // _PMENU_HH_


syntax highlighted by Code2HTML, v. 0.9.1