added keyboard navigation

This commit is contained in:
fluxgen 2003-07-02 05:26:45 +00:00
parent 2737e94b24
commit 10d70ecd54
2 changed files with 168 additions and 6 deletions

View file

@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Menu.cc,v 1.24 2003/05/24 12:34:16 rathnor Exp $
// $Id: Menu.cc,v 1.25 2003/07/02 05:26:14 fluxgen Exp $
//use GNU extensions
#ifndef _GNU_SOURCE
@ -39,6 +39,8 @@
#include "Transparent.hh"
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@ -76,10 +78,12 @@ namespace FbTk {
static Menu *shown = 0;
unsigned char Menu::s_alpha = 255;
Menu *Menu::s_focused = 0;
Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl):
m_theme(tm),
m_screen_num(screen_num),
m_prev_focused_window(0),
m_image_ctrl(imgctrl),
m_display(FbTk::App::instance()->display()),
m_parent(0),
@ -143,13 +147,15 @@ Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl):
XSetWindowAttributes attrib;
attrib.override_redirect = True;
attrib.event_mask = ButtonPressMask | ButtonReleaseMask |
ButtonMotionMask | KeyPressMask | ExposureMask;
ButtonMotionMask | KeyPressMask | ExposureMask | FocusChangeMask;
//create menu window
menu.window = XCreateWindow(m_display, RootWindow(m_display, screen_num),
menu.x, menu.y, menu.width, menu.height,
0, CopyFromParent,
InputOutput, CopyFromParent, attrib_mask, &attrib);
// strip focus change mask from attrib, since we should only use it with main window
attrib.event_mask ^= FocusChangeMask;
FbTk::EventManager &evm = *FbTk::EventManager::instance();
evm.add(*this, menu.window);
@ -199,7 +205,8 @@ Menu::~Menu() {
evm.remove(menu.title);
evm.remove(menu.frame);
evm.remove(menu.window);
if (s_focused == this)
s_focused = 0;
}
int Menu::insert(const char *label, RefCount<Command> &cmd, int pos) {
@ -280,6 +287,80 @@ void Menu::lower() {
menu.window.lower();
}
void Menu::nextItem() {
if (which_press == menuitems.size() - 1)
return;
int old_which_press = which_press;
if (old_which_press >= 0 &&
old_which_press < menuitems.size() &&
menuitems[old_which_press] != 0) {
if (menuitems[old_which_press]->submenu()) {
// we need to do this explicitly on the menu.window
// since it might hide the parent if we use Menu::hide
menuitems[old_which_press]->submenu()->menu.window.hide();
}
drawItem(old_which_press, false, true, true);
}
// restore old in case we changed which_press
which_press = old_which_press;
if (which_press < 0 || which_press >= menuitems.size())
which_press = 0;
else if (which_press < menuitems.size() - 1)
which_press++;
if (menuitems[which_press] == 0)
return;
if (menuitems[which_press]->submenu())
drawSubmenu(which_press);
else
drawItem(which_press, true, true, true);
#ifdef DEBUG
cerr<<__FILE__<<"("<<__FUNCTION__<<")"<<endl;
cerr<<"which_press = "<<which_press<<endl;
#endif // DEBUG
}
void Menu::prevItem() {
int old_which_press = which_press;
if (old_which_press >= 0 && old_which_press < menuitems.size()) {
if (menuitems[old_which_press]->submenu()) {
// we need to do this explicitly on the menu.window
// since it might hide the parent if we use Menu::hide
menuitems[old_which_press]->submenu()->menu.window.hide();
}
drawItem(old_which_press, false, true, true);
}
// restore old in case we changed which_press
which_press = old_which_press;
if (which_press < 0 || which_press >= menuitems.size())
which_press = 0;
else if (which_press - 1 >= 0)
which_press--;
if (menuitems[which_press] != 0) {
if (menuitems[which_press]->submenu())
drawSubmenu(which_press);
else
drawItem(which_press, true, true, true);
}
#ifdef DEBUG
cerr<<__FILE__<<"("<<__FUNCTION__<<")"<<endl;
cerr<<"which_press = "<<which_press<<endl;
#endif // DEBUG
}
void Menu::disableTitle() {
setTitleVisibility(false);
}
@ -486,8 +567,18 @@ void Menu::hide() {
p->internal_hide();
} else
internal_hide();
}
void Menu::grabInputFocus() {
s_focused = this;
// grab input focus
menu.window.setInputFocus(RevertToPointerRoot, CurrentTime);
}
void Menu::clearWindow() {
menu.window.clear();
menu.title.clear();
@ -925,9 +1016,22 @@ bool Menu::isItemEnabled(unsigned int index) const {
return item->isEnabled();
}
void Menu::handleEvent(XEvent &event) {
if (event.type == FocusOut) {
cerr<<"Focus out"<<endl;
if (s_focused == this)
s_focused = 0;
} else if (event.type == FocusIn) {
cerr<<"Focus in"<<endl;
if (s_focused != this)
s_focused = this;
}
}
void Menu::buttonPressEvent(XButtonEvent &be) {
grabInputFocus();
if (be.window == menu.frame && menu.item_h != 0 && menu.item_w != 0) {
int sbl = (be.x / menu.item_w), i = (be.y / menu.item_h);
int w = (sbl * menu.persub) + i;
@ -1025,7 +1129,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
if ((i != which_press || sbl != which_sbl) &&
(w < static_cast<int>(menuitems.size()) && w >= 0)) {
if (which_press != -1 && which_sbl != -1) {
int p = (which_sbl * menu.persub) + which_press;
int p = which_sbl * menu.persub + which_press;
MenuItem *item = menuitems[p];
drawItem(p, false, true, true);
@ -1155,6 +1259,54 @@ void Menu::leaveNotifyEvent(XCrossingEvent &ce) {
}
}
void Menu::keyPressEvent(XKeyEvent &event) {
KeySym ks;
char keychar[1];
XLookupString(&event, keychar, 1, &ks, 0);
// a modifier key by itself doesn't do anything
if (IsModifierKey(ks))
return;
if (event.state) // dont handle modifier with normal key
return;
switch (ks) {
case XK_Up:
prevItem();
break;
case XK_Down:
nextItem();
break;
case XK_Left:
if (which_press >= 0 && which_press < menuitems.size() &&
m_parent != 0) {
if (menuitems[which_press]->submenu())
menuitems[which_press]->submenu()->menu.window.hide();
drawItem(which_press, false, true, true);
m_parent->grabInputFocus();
}
break;
case XK_Right:
if (which_press >= 0 && which_press < menuitems.size() &&
menuitems[which_press]->submenu()) {
menuitems[which_press]->submenu()->grabInputFocus();
menuitems[which_press]->submenu()->which_press = -1;
menuitems[which_press]->submenu()->nextItem();
}
break;
case XK_Escape:
hide();
break;
case XK_Return:
if (which_press >= 0 && which_press < menuitems.size()) {
menuitems[which_press]->click(1, event.time);
itemSelected(1, which_press);
update();
}
break;
default:
break;
}
}
void Menu::reconfigure() {
m_need_update = true; // redraw items

View file

@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Menu.hh,v 1.15 2003/05/13 00:24:00 fluxgen Exp $
// $Id: Menu.hh,v 1.16 2003/07/02 05:26:45 fluxgen Exp $
#ifndef FBTK_MENU_HH
#define FBTK_MENU_HH
@ -85,6 +85,10 @@ public:
virtual void raise();
/// lower this window
virtual void lower();
/// select next item
void nextItem();
/// select previous item
void prevItem();
void disableTitle();
void enableTitle();
@ -95,14 +99,17 @@ public:
@name event handlers
*/
//@{
void handleEvent(XEvent &event);
void buttonPressEvent(XButtonEvent &bp);
void buttonReleaseEvent(XButtonEvent &br);
void motionNotifyEvent(XMotionEvent &mn);
void enterNotifyEvent(XCrossingEvent &en);
void leaveNotifyEvent(XCrossingEvent &ce);
void exposeEvent(XExposeEvent &ee);
void keyPressEvent(XKeyEvent &ke);
//@}
/// get input focus
void grabInputFocus();
void reconfigure();
/// set label string
void setLabel(const char *labelstr);
@ -142,6 +149,7 @@ public:
bool isItemSelected(unsigned int index) const;
bool isItemEnabled(unsigned int index) const;
static unsigned char alpha() { return s_alpha; }
static Menu *focused() { return s_focused; }
/// @return menuitem at index
inline const MenuItem *find(unsigned int index) const { return menuitems[index]; }
inline MenuItem *find(unsigned int index) { return menuitems[index]; }
@ -170,6 +178,7 @@ private:
const MenuTheme &m_theme;
Display *m_display;
const int m_screen_num;
Window m_prev_focused_window;
Menu *m_parent;
ImageControl &m_image_ctrl;
Menuitems menuitems;
@ -206,6 +215,7 @@ private:
std::auto_ptr<Transparent> m_trans;
Drawable m_root_pm;
static unsigned char s_alpha;
static Menu *s_focused; ///< holds current input focused menu, so one can determine if a menu is focused
FbPixmap m_frame_pm;
bool m_need_update;
};