/* ParaGUI - crossplatform widgetset Copyright (C) 2000,2001,2002 Alexander Pipelka This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Alexander Pipelka pipelka@teleweb.at Last Update: $Author: braindead $ Update Date: $Date: 2003/01/04 21:13:38 $ Source File: $Source: /cvsroot/paragui/paragui/include/pgpopupmenu.h,v $ CVS/RCS Revision: $Revision: 1.3.6.3 $ Status: $State: Exp $ */ #ifndef PG_POPUPMENU_H #define PG_POPUPMENU_H #ifdef SWIG %include "swigcommon.h" %module pgpopupmenu %{ #include "pgpopupmenu.h" %} #endif #include "pgthemewidget.h" #include #include #ifdef HASH_MAP_INC # include HASH_MAP_INC #else # include #endif /** * @author Marek Habersack * * @short A stand-alone or attached popup menu * * A popup menu that can be attached to a menu bar or used * stand-alone. In the first case, the widget sizes itself so that * only the caption is visible, the menu items remain hidden until * menu is activated. In the latter case menu sizes itself to * encompass all of its items unless the menu size would exceed the * space between the menu origin and the edge of the screen. In such * case, menu displays a "scroller" button at the bottom. * * @todo implement the scroller code (menu scrolling when it exceeds the * screen height/width - a kind of specialized widgetlist). Should * display a scroller icon at the bottom/top of the popup menu - a'la * w2k. * @todo keyboard handling (accelerators, ESC/ENTER & arrows) */ class DECLSPEC PG_PopupMenu : public PG_ThemeWidget { public: /** * @author Marek Habersack * * @short A menu item data structure * * Even though implemented as a class, MenuItem is not intended to be a new * kind of widget - therefore it is derived only from PG_Rect for * convenience. The idea is to have a "smart" data type (or a dumb class, * if you prefer) that knows how to perform simple and specific actions on * itself. The intention is to provide PG_PopupMenu with a fast mechanism * for processing menu items - if MenuItem was derived from any of ParaGUI * classes it would incurr unnecessary processing overhead. * * @todo better separator code * @todo icon drawing */ #ifndef SWIG class MenuItem : public PG_Rect, public PG_MessageObject { public: // types enum MI_FLAGS { MIF_NONE = 0, MIF_DISABLED = 0x01, MIF_SEPARATOR = 0x02, MIF_SUBMENU = 0x04 }; public: // methods MenuItem(PG_PopupMenu *parent, char *caption, int id, MI_FLAGS flags); MenuItem(PG_PopupMenu *parent, char *caption, PG_PopupMenu *submenu); ~MenuItem(); bool measureItem(PG_Rect* rect, bool full = false); bool isPointInside(int x, int y); inline void moveTo(int x, int y); inline SDL_Surface* getNormal() const; inline SDL_Surface* getDisabled() const; inline SDL_Surface* getSelected() const; bool paintNormal(SDL_Surface *canvas, SDL_Color *tcol, SDL_Color *scol = 0); bool paintDisabled(SDL_Surface *canvas, SDL_Color *tcol, SDL_Color *scol = 0); bool paintSelected(SDL_Surface *canvas, SDL_Color *tcol, SDL_Color *scol = 0); inline void disable(); inline void enable(); inline bool isDisabled() const; inline bool isEnabled() const; inline void select(); inline void unselect(); inline bool isSelected() const; inline bool isSeparator() const; inline bool isSubMenu() const; inline bool isMute() const; inline int Width() const; inline int Height() const; inline int getId() const; inline PG_PopupMenu *getSubMenu() const; inline const string& getCaption() const; inline operator PG_Point const&() const; private: // methods void initItem(); bool renderSurface(SDL_Surface *canvas, SDL_Surface **text, SDL_Color *tcol, SDL_Color *scol = 0); bool isValidRect(); protected: // data unsigned myFlags; string myCaption; PG_PopupMenu *myParent; PG_PopupMenu *mySubMenu; int myId; SDL_Surface *sNormal; SDL_Surface *sSelected; SDL_Surface *sDisabled; bool selected; private: // data bool needRecalc; SDL_Rect blitRect; PG_Point myPoint; }; #ifndef DOXYGEN_SKIP class item_with_id : public unary_function { int id; public: explicit item_with_id(int i) : id(i) {} bool operator() (const MenuItem* const mi) const { return mi->getId() == id; } }; #endif // DOXYGEN_SKIP #endif // SWIG public: // methods PG_PopupMenu(PG_Widget *parent, int x, int y, char *caption, char *style = "PopupMenu"); ~PG_PopupMenu(); /** @name Add a new menu item to this menu * * Constructs a new menu item using the provided parameters and * then adds the item to this menu. *@{ */ #ifndef SWIG /** * Adds a menu item whose handler (if any) is set to be a stand-alone * function. * * @param caption the item caption * @param ID the item identifier * @param handler function to handle the menu item click * @param data application-specific data associated with the menu * item action. * @param flags menu item flags * */ PG_PopupMenu& addMenuItem(char *caption, int ID, MSG_CALLBACK handler = 0, void *data = 0, MenuItem::MI_FLAGS flags = MenuItem::MIF_NONE); /** * Adds a menu item whose handler (if any) is set to be a member * method of some object. * * @param caption the item caption * @param ID the item identifier * @param handler function to handle the menu item click * @param obj object the 'handler' function lives in. * @param data application-specific data associated with the menu * item action. * @param flags menu item flags * * @note @code obj @endcode cannot be 0 if @code handler @endcode is present */ PG_PopupMenu& addMenuItem(char *caption, int ID, MSG_CALLBACK_OBJ handler, PG_EventObject *obj, void *data = 0, MenuItem::MI_FLAGS flags = MenuItem::MIF_NONE); PG_PopupMenu& addMenuItem(char *caption, PG_PopupMenu *sub, MenuItem::MI_FLAGS flags = MenuItem::MIF_SUBMENU); #endif // SWIG /** * @return a reference to this menu *@} */ PG_PopupMenu& addSeparator(); bool SetMenuItemHandler(int id,MSG_CALLBACK handler,void *data); bool SetMenuItemEventObject(int id,PG_EventObject* calledobj, MSG_CALLBACK_OBJ cbfunc, void *clientdata); inline int maxItemWidth() const; void disableItem(int dd); void enableItem(int id); /** * Modal popup menu will be shown - i.e. all mouse/keyboard events will * be captured by the menu and until the user selects any menu item (or * cancels the menu by pressing ESC) no other widget will be * accessible. If @code x @endcoce and @code y @endcode are absent, menu is popped up at * its current position. * * @param x xpos where the menu should pop up * @param y ypos where the menu should pop up * */ void trackMenu(int x = -1, int y = -1); protected: // methods #ifndef SWIG typedef list::iterator MII; #endif // SWIG // reimplemented void eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst); void eventMouseEnter(); void eventMouseLeave(); bool eventMouseMotion(const SDL_MouseMotionEvent *motion); bool eventMouseButtonDown(const SDL_MouseButtonEvent *button); bool eventMouseButtonUp(const SDL_MouseButtonEvent *button); bool eventKeyDown(const SDL_KeyboardEvent *key); void eventMoveWidget(int x, int y); void eventShow(); void eventHide(); void LoadThemeStyle(const char *widgettype); void LoadThemeStyle(const char *widgettype, const char *objectname); // own virtual bool getCaptionHeight(PG_Rect &rect, bool constructing = false); virtual void recalcRect(); virtual void handleClick(int x, int y); virtual void enslave(PG_PopupMenu *master); virtual void liberate(); private: // methods #ifndef SWIG bool selectItem(MenuItem *item, MII iter); bool handleMotion(PG_Point const&); void appendItem(MenuItem *item); #endif //SWIG protected: // data #ifndef SWIG list items; /** the menu items collection */ string myCaption; /** menu caption */ #endif //SWIG SDL_Color captionActiveColor; SDL_Color captionInactiveColor; SDL_Color miNormalColor; SDL_Color miSelectedColor; SDL_Color miDisabledColor; SDL_Color sepNormalColor; SDL_Color sepShadowColor; int xPadding; int yPadding; private: // data PG_Rect captionRect; PG_Rect actionRect; PG_Gradient *miGradients[3]; SDL_Surface *miBackgrounds[3]; int miBkModes[3]; Uint8 miBlends[3]; int itemHeight; int lastH; MenuItem *selected; bool tracking; bool wasTracking; bool buttonDown; MII stop; MII start; MII current; PG_PopupMenu *activeSub; PG_PopupMenu *myMaster; MenuItem *subParent; }; #ifndef SWIG inline int PG_PopupMenu::maxItemWidth() const { return w - xPadding; } inline void PG_PopupMenu::MenuItem::moveTo(int _x, int _y) { myPoint.x = x = _x; myPoint.y = y = _y; }; inline SDL_Surface* PG_PopupMenu::MenuItem::getNormal() const { return sNormal; } inline SDL_Surface* PG_PopupMenu::MenuItem::getDisabled() const { return sDisabled; } inline SDL_Surface* PG_PopupMenu::MenuItem::getSelected() const { return sSelected; } inline void PG_PopupMenu::MenuItem::disable() { myFlags |= MIF_DISABLED; } inline void PG_PopupMenu::MenuItem::enable() { myFlags &= ~MIF_DISABLED; } inline bool PG_PopupMenu::MenuItem::isDisabled() const { return (myFlags & MIF_DISABLED); } inline bool PG_PopupMenu::MenuItem::isEnabled() const { return !(myFlags & MIF_DISABLED); } inline void PG_PopupMenu::MenuItem::select() { selected = true; } inline void PG_PopupMenu::MenuItem::unselect() { selected = false; } inline bool PG_PopupMenu::MenuItem::isSelected() const { return selected; } inline bool PG_PopupMenu::MenuItem::isSeparator() const { return (myFlags & MIF_SEPARATOR); } inline bool PG_PopupMenu::MenuItem::isSubMenu() const { return (myFlags & MIF_SUBMENU); } inline bool PG_PopupMenu::MenuItem::isMute() const { return ((myFlags & MIF_DISABLED) || (myFlags & MIF_SEPARATOR)); } inline int PG_PopupMenu::MenuItem::Width() const { return w; } inline int PG_PopupMenu::MenuItem::Height() const { return h; } inline int PG_PopupMenu::MenuItem::getId() const { return myId; } inline PG_PopupMenu *PG_PopupMenu::MenuItem::getSubMenu() const { return mySubMenu; } inline const string& PG_PopupMenu::MenuItem::getCaption() const { return myCaption; } inline PG_PopupMenu::MenuItem::operator PG_Point const&() const { return myPoint; } #endif // SWIG #endif // PG_POPUPMENU_H