1 // Menu.hh for FbTk - Fluxbox Toolkit
2 // Copyright (c) 2001 - 2004 Henrik Kinnunen (fluxgen at fluxbox dot org)
3 //
4 // Basemenu.hh for Blackbox - an X11 Window manager
5 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
24 
25 // $Id: Menu.hh 3954 2005-04-26 01:41:55Z simonb $
26 
27 #ifndef	 FBTK_MENU_HH
28 #define	 FBTK_MENU_HH
29 
30 #include <X11/Xlib.h>
31 #include <vector>
32 #include <string>
33 #include <memory>
34 
35 #include "FbWindow.hh"
36 #include "EventHandler.hh"
37 #include "RefCount.hh"
38 #include "Command.hh"
39 #include "Observer.hh"
40 #include "FbPixmap.hh"
41 #include "MenuTheme.hh"
42 #include "Timer.hh"
43 
44 namespace FbTk {
45 
46 class MenuItem;
47 class ImageControl;
48 
49 ///   Base class for menus
50 class Menu: public FbTk::EventHandler, FbTk::FbWindowRenderer, protected FbTk::Observer {
51 public:
52     enum Alignment{ ALIGNDONTCARE = 1, ALIGNTOP, ALIGNBOTTOM };
53     enum { RIGHT = 1, LEFT };
54 
55     /**
56        Bullet type
57     */
58     enum { EMPTY = 0, SQUARE, TRIANGLE, DIAMOND };
59 
60     Menu(MenuTheme &tm, ImageControl &imgctrl);
61     virtual ~Menu();
62 
63     /**
64        @name manipulators
65     */
66     //@{
67     /// add a menu item with a label and a command
68     int insert(const char *label, RefCount<Command> &cmd, int pos=-1);
69     /// add empty menu item
70     int insert(const char *label, int pos=-1);
71     /// add submenu
72     int insert(const char *label, Menu *submenu, int pos= -1);
73     /// add menu item
74     int insert(MenuItem *item, int pos=-1);
75     /// remove an item
76     int remove(unsigned int item);
77     /// remove all items
78     void removeAll();
setInternalMenu(bool val=true)79     inline void setInternalMenu(bool val = true) { m_internal_menu = val; }
setAlignment(Alignment a)80     inline void setAlignment(Alignment a) { m_alignment = a; }
setTorn()81     inline void setTorn() { m_torn = true; }
removeParent()82     inline void removeParent() { if (m_internal_menu) m_parent = 0; }
83     /// raise this window
84     virtual void raise();
85     /// lower this window
86     virtual void lower();
87     /// select next item
88     void nextItem();
89     /// select previous item
90     void prevItem();
91     void enterSubmenu();
92     void enterParent();
93 
94     void disableTitle();
95     void enableTitle();
96 
97     void setScreen(int x, int y, int w, int h);
98 
99     /**
100        @name event handlers
101     */
102     //@{
103     void handleEvent(XEvent &event);
104     void buttonPressEvent(XButtonEvent &bp);
105     void buttonReleaseEvent(XButtonEvent &br);
106     void motionNotifyEvent(XMotionEvent &mn);
107     void enterNotifyEvent(XCrossingEvent &en);
108     void leaveNotifyEvent(XCrossingEvent &ce);
109     void exposeEvent(XExposeEvent &ee);
110     void keyPressEvent(XKeyEvent &ke);
111     //@}
112     /// get input focus
113     void grabInputFocus();
114     virtual void reconfigure();
115     /// set label string
116     void setLabel(const char *labelstr);
117     /// move menu to x,y
118     void move(int x, int y);
119     virtual void updateMenu(int active_index = -1);
120     void setItemSelected(unsigned int index, bool val);
121     void setItemEnabled(unsigned int index, bool val);
setMinimumSublevels(int m)122     inline void setMinimumSublevels(int m) { menu.minsub = m; }
123     virtual void drawSubmenu(unsigned int index);
124     /// show menu
125     virtual void show();
126     /// hide menu
127     virtual void hide();
128     virtual void clearWindow();
setActiveIndex(int index)129     void setActiveIndex(int index) { m_active_index = index; }
130     /*@}*/
131 
132     /**
133        @name accessors
134     */
135     //@{
activeIndex() const136     inline int activeIndex() const { return m_active_index; }
isTorn() const137     inline bool isTorn() const { return m_torn; }
isVisible() const138     inline bool isVisible() const { return m_visible; }
screenNumber() const139     inline int screenNumber() const { return menu.window.screenNumber(); }
window() const140     inline Window window() const { return menu.window.window(); }
fbwindow()141     inline FbWindow &fbwindow() { return menu.window; }
fbwindow() const142     inline const FbWindow &fbwindow() const { return menu.window; }
titleWindow()143     inline FbWindow &titleWindow() { return menu.title; }
frameWindow()144     inline FbWindow &frameWindow() { return menu.frame; }
label() const145     inline const std::string &label() const { return menu.label; }
x() const146     inline int x() const { return menu.window.x(); }
y() const147     inline int y() const { return menu.window.y(); }
width() const148     inline unsigned int width() const { return menu.window.width(); }
height() const149     inline unsigned int height() const { return menu.window.height(); }
numberOfItems() const150     inline unsigned int numberOfItems() const { return menuitems.size(); }
currentSubmenu() const151     inline int currentSubmenu() const { return m_which_sub; }
152     bool hasSubmenu(unsigned int index) const;
153     bool isItemSelected(unsigned int index) const;
154     bool isItemEnabled(unsigned int index) const;
155     bool isItemSelectable(unsigned int index) const;
theme() const156     inline const MenuTheme &theme() const { return m_theme; }
alpha() const157     inline unsigned char alpha() const { return theme().alpha(); }
focused()158     inline static Menu *focused() { return s_focused; }
159     /// @return menuitem at index
find(unsigned int index) const160     inline const MenuItem *find(unsigned int index) const { return menuitems[index]; }
find(unsigned int index)161     inline MenuItem *find(unsigned int index) { return menuitems[index]; }
162     //@}
163     /// @return true if index is valid
validIndex(int index) const164     inline bool validIndex(int index) const { return (index < static_cast<int>(numberOfItems()) && index >= 0); }
165 
parent()166     inline Menu *parent() { return m_parent; }
parent() const167     inline const Menu *parent() const { return m_parent; }
168 
169     void renderForeground(FbWindow &win, FbDrawable &drawable);
170 
171 protected:
172 
setTitleVisibility(bool b)173     inline void setTitleVisibility(bool b) {
174         m_title_vis = b; m_need_update = true;
175         if (!b)
176             titleWindow().lower();
177         else
178             titleWindow().raise();
179     }
180 
itemSelected(int button,unsigned int index)181     virtual void itemSelected(int button, unsigned int index) { }
182     // renders item onto pm
183     int drawItem(FbDrawable &pm, unsigned int index,
184                  bool highlight = false,
185                  bool exclusive_drawable = false);
186     void clearItem(int index, bool clear = true);
187     void highlightItem(int index);
188     virtual void redrawTitle(FbDrawable &pm);
189     virtual void redrawFrame(FbDrawable &pm);
190 
191     virtual void internal_hide();
192 
193     void update(FbTk::Subject *);
194 
195 private:
196 
197     void openSubmenu();
198     void closeMenu();
199     void startHide();
200     void stopHide();
201 
202 
203     typedef std::vector<MenuItem *> Menuitems;
204     MenuTheme &m_theme;
205     Menu *m_parent;
206     ImageControl &m_image_ctrl;
207     Menuitems menuitems;
208 
209     int m_screen_x, m_screen_y;
210     int m_screen_width, m_screen_height;
211     bool m_moving; ///< if we're moving/draging or not
212     bool m_visible; ///< menu visibility
213     bool m_torn; ///< torn from parent
214     bool m_internal_menu; ///< whether we should destroy this menu or if it's managed somewhere else
215     bool m_title_vis; ///< title visibility
216     bool m_shifted; ///< if the menu is shifted to the other side of the parent
217 
218     int m_which_sub, m_which_press, m_which_sbl;
219     Alignment m_alignment;
220 
221     struct _menu {
222         Pixmap frame_pixmap, title_pixmap, hilite_pixmap;
223         FbTk::FbWindow window, frame, title;
224 
225         std::string label;
226         int x_move, y_move, x_shift, y_shift, sublevels, persub, minsub,
227             grab_x, grab_y;
228 
229         unsigned int frame_h, item_w;
230     } menu;
231 
232     int m_active_index; ///< current highlighted index
233 
234     Drawable m_root_pm;
235     static Menu *s_focused; ///< holds current input focused menu, so one can determine if a menu is focused
236     bool m_need_update;
237     Timer m_submenu_timer;
238     Timer m_hide_timer;
239 };
240 
241 } // end namespace FbTk
242 
243 #endif // FBTK_MENU_HH
244