aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk/Menu.cc
diff options
context:
space:
mode:
authorfluxgen <fluxgen>2003-07-02 05:26:45 (GMT)
committerfluxgen <fluxgen>2003-07-02 05:26:45 (GMT)
commit10d70ecd54fc678499786ab84279223c5bd776e3 (patch)
tree8b51bbca3c363c022db96e7ef0dd31fc2913a66e /src/FbTk/Menu.cc
parent2737e94b242ffc38f4d6760512ba794755603bf7 (diff)
downloadfluxbox-10d70ecd54fc678499786ab84279223c5bd776e3.zip
fluxbox-10d70ecd54fc678499786ab84279223c5bd776e3.tar.bz2
added keyboard navigation
Diffstat (limited to 'src/FbTk/Menu.cc')
-rw-r--r--src/FbTk/Menu.cc160
1 files changed, 156 insertions, 4 deletions
diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc
index 04bcc03..c953be9 100644
--- a/src/FbTk/Menu.cc
+++ b/src/FbTk/Menu.cc
@@ -22,7 +22,7 @@
22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23// DEALINGS IN THE SOFTWARE. 23// DEALINGS IN THE SOFTWARE.
24 24
25// $Id: Menu.cc,v 1.24 2003/05/24 12:34:16 rathnor Exp $ 25// $Id: Menu.cc,v 1.25 2003/07/02 05:26:14 fluxgen Exp $
26 26
27//use GNU extensions 27//use GNU extensions
28#ifndef _GNU_SOURCE 28#ifndef _GNU_SOURCE
@@ -39,6 +39,8 @@
39#include "Transparent.hh" 39#include "Transparent.hh"
40 40
41#include <X11/Xatom.h> 41#include <X11/Xatom.h>
42#include <X11/keysym.h>
43
42#include <cstdio> 44#include <cstdio>
43#include <cstdlib> 45#include <cstdlib>
44#include <cstring> 46#include <cstring>
@@ -76,10 +78,12 @@ namespace FbTk {
76static Menu *shown = 0; 78static Menu *shown = 0;
77 79
78unsigned char Menu::s_alpha = 255; 80unsigned char Menu::s_alpha = 255;
81Menu *Menu::s_focused = 0;
79 82
80Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl): 83Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl):
81 m_theme(tm), 84 m_theme(tm),
82 m_screen_num(screen_num), 85 m_screen_num(screen_num),
86 m_prev_focused_window(0),
83 m_image_ctrl(imgctrl), 87 m_image_ctrl(imgctrl),
84 m_display(FbTk::App::instance()->display()), 88 m_display(FbTk::App::instance()->display()),
85 m_parent(0), 89 m_parent(0),
@@ -143,13 +147,15 @@ Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl):
143 XSetWindowAttributes attrib; 147 XSetWindowAttributes attrib;
144 attrib.override_redirect = True; 148 attrib.override_redirect = True;
145 attrib.event_mask = ButtonPressMask | ButtonReleaseMask | 149 attrib.event_mask = ButtonPressMask | ButtonReleaseMask |
146 ButtonMotionMask | KeyPressMask | ExposureMask; 150 ButtonMotionMask | KeyPressMask | ExposureMask | FocusChangeMask;
147 151
148 //create menu window 152 //create menu window
149 menu.window = XCreateWindow(m_display, RootWindow(m_display, screen_num), 153 menu.window = XCreateWindow(m_display, RootWindow(m_display, screen_num),
150 menu.x, menu.y, menu.width, menu.height, 154 menu.x, menu.y, menu.width, menu.height,
151 0, CopyFromParent, 155 0, CopyFromParent,
152 InputOutput, CopyFromParent, attrib_mask, &attrib); 156 InputOutput, CopyFromParent, attrib_mask, &attrib);
157 // strip focus change mask from attrib, since we should only use it with main window
158 attrib.event_mask ^= FocusChangeMask;
153 159
154 FbTk::EventManager &evm = *FbTk::EventManager::instance(); 160 FbTk::EventManager &evm = *FbTk::EventManager::instance();
155 evm.add(*this, menu.window); 161 evm.add(*this, menu.window);
@@ -199,7 +205,8 @@ Menu::~Menu() {
199 evm.remove(menu.title); 205 evm.remove(menu.title);
200 evm.remove(menu.frame); 206 evm.remove(menu.frame);
201 evm.remove(menu.window); 207 evm.remove(menu.window);
202 208 if (s_focused == this)
209 s_focused = 0;
203} 210}
204 211
205int Menu::insert(const char *label, RefCount<Command> &cmd, int pos) { 212int Menu::insert(const char *label, RefCount<Command> &cmd, int pos) {
@@ -280,6 +287,80 @@ void Menu::lower() {
280 menu.window.lower(); 287 menu.window.lower();
281} 288}
282 289
290void Menu::nextItem() {
291 if (which_press == menuitems.size() - 1)
292 return;
293
294 int old_which_press = which_press;
295
296 if (old_which_press >= 0 &&
297 old_which_press < menuitems.size() &&
298 menuitems[old_which_press] != 0) {
299 if (menuitems[old_which_press]->submenu()) {
300 // we need to do this explicitly on the menu.window
301 // since it might hide the parent if we use Menu::hide
302 menuitems[old_which_press]->submenu()->menu.window.hide();
303 }
304 drawItem(old_which_press, false, true, true);
305 }
306
307 // restore old in case we changed which_press
308 which_press = old_which_press;
309 if (which_press < 0 || which_press >= menuitems.size())
310 which_press = 0;
311 else if (which_press < menuitems.size() - 1)
312 which_press++;
313
314
315 if (menuitems[which_press] == 0)
316 return;
317
318 if (menuitems[which_press]->submenu())
319 drawSubmenu(which_press);
320 else
321 drawItem(which_press, true, true, true);
322
323#ifdef DEBUG
324 cerr<<__FILE__<<"("<<__FUNCTION__<<")"<<endl;
325 cerr<<"which_press = "<<which_press<<endl;
326#endif // DEBUG
327
328}
329
330void Menu::prevItem() {
331
332 int old_which_press = which_press;
333
334 if (old_which_press >= 0 && old_which_press < menuitems.size()) {
335 if (menuitems[old_which_press]->submenu()) {
336 // we need to do this explicitly on the menu.window
337 // since it might hide the parent if we use Menu::hide
338 menuitems[old_which_press]->submenu()->menu.window.hide();
339 }
340 drawItem(old_which_press, false, true, true);
341 }
342 // restore old in case we changed which_press
343 which_press = old_which_press;
344
345 if (which_press < 0 || which_press >= menuitems.size())
346 which_press = 0;
347 else if (which_press - 1 >= 0)
348 which_press--;
349
350 if (menuitems[which_press] != 0) {
351 if (menuitems[which_press]->submenu())
352 drawSubmenu(which_press);
353 else
354 drawItem(which_press, true, true, true);
355 }
356
357#ifdef DEBUG
358 cerr<<__FILE__<<"("<<__FUNCTION__<<")"<<endl;
359 cerr<<"which_press = "<<which_press<<endl;
360#endif // DEBUG
361
362}
363
283void Menu::disableTitle() { 364void Menu::disableTitle() {
284 setTitleVisibility(false); 365 setTitleVisibility(false);
285} 366}
@@ -486,8 +567,18 @@ void Menu::hide() {
486 p->internal_hide(); 567 p->internal_hide();
487 } else 568 } else
488 internal_hide(); 569 internal_hide();
570
571}
572
573void Menu::grabInputFocus() {
574 s_focused = this;
575
576 // grab input focus
577 menu.window.setInputFocus(RevertToPointerRoot, CurrentTime);
578
489} 579}
490 580
581
491void Menu::clearWindow() { 582void Menu::clearWindow() {
492 menu.window.clear(); 583 menu.window.clear();
493 menu.title.clear(); 584 menu.title.clear();
@@ -925,9 +1016,22 @@ bool Menu::isItemEnabled(unsigned int index) const {
925 return item->isEnabled(); 1016 return item->isEnabled();
926} 1017}
927 1018
1019void Menu::handleEvent(XEvent &event) {
1020 if (event.type == FocusOut) {
1021 cerr<<"Focus out"<<endl;
1022 if (s_focused == this)
1023 s_focused = 0;
1024 } else if (event.type == FocusIn) {
1025 cerr<<"Focus in"<<endl;
1026 if (s_focused != this)
1027 s_focused = this;
1028 }
1029}
928 1030
929void Menu::buttonPressEvent(XButtonEvent &be) { 1031void Menu::buttonPressEvent(XButtonEvent &be) {
1032 grabInputFocus();
930 if (be.window == menu.frame && menu.item_h != 0 && menu.item_w != 0) { 1033 if (be.window == menu.frame && menu.item_h != 0 && menu.item_w != 0) {
1034
931 int sbl = (be.x / menu.item_w), i = (be.y / menu.item_h); 1035 int sbl = (be.x / menu.item_w), i = (be.y / menu.item_h);
932 int w = (sbl * menu.persub) + i; 1036 int w = (sbl * menu.persub) + i;
933 1037
@@ -1025,7 +1129,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
1025 if ((i != which_press || sbl != which_sbl) && 1129 if ((i != which_press || sbl != which_sbl) &&
1026 (w < static_cast<int>(menuitems.size()) && w >= 0)) { 1130 (w < static_cast<int>(menuitems.size()) && w >= 0)) {
1027 if (which_press != -1 && which_sbl != -1) { 1131 if (which_press != -1 && which_sbl != -1) {
1028 int p = (which_sbl * menu.persub) + which_press; 1132 int p = which_sbl * menu.persub + which_press;
1029 MenuItem *item = menuitems[p]; 1133 MenuItem *item = menuitems[p];
1030 1134
1031 drawItem(p, false, true, true); 1135 drawItem(p, false, true, true);
@@ -1155,6 +1259,54 @@ void Menu::leaveNotifyEvent(XCrossingEvent &ce) {
1155 } 1259 }
1156} 1260}
1157 1261
1262void Menu::keyPressEvent(XKeyEvent &event) {
1263 KeySym ks;
1264 char keychar[1];
1265 XLookupString(&event, keychar, 1, &ks, 0);
1266 // a modifier key by itself doesn't do anything
1267 if (IsModifierKey(ks))
1268 return;
1269 if (event.state) // dont handle modifier with normal key
1270 return;
1271
1272 switch (ks) {
1273 case XK_Up:
1274 prevItem();
1275 break;
1276 case XK_Down:
1277 nextItem();
1278 break;
1279 case XK_Left:
1280 if (which_press >= 0 && which_press < menuitems.size() &&
1281 m_parent != 0) {
1282 if (menuitems[which_press]->submenu())
1283 menuitems[which_press]->submenu()->menu.window.hide();
1284 drawItem(which_press, false, true, true);
1285 m_parent->grabInputFocus();
1286 }
1287 break;
1288 case XK_Right:
1289 if (which_press >= 0 && which_press < menuitems.size() &&
1290 menuitems[which_press]->submenu()) {
1291 menuitems[which_press]->submenu()->grabInputFocus();
1292 menuitems[which_press]->submenu()->which_press = -1;
1293 menuitems[which_press]->submenu()->nextItem();
1294 }
1295 break;
1296 case XK_Escape:
1297 hide();
1298 break;
1299 case XK_Return:
1300 if (which_press >= 0 && which_press < menuitems.size()) {
1301 menuitems[which_press]->click(1, event.time);
1302 itemSelected(1, which_press);
1303 update();
1304 }
1305 break;
1306 default:
1307 break;
1308 }
1309}
1158 1310
1159void Menu::reconfigure() { 1311void Menu::reconfigure() {
1160 m_need_update = true; // redraw items 1312 m_need_update = true; // redraw items