added keyboard navigation
This commit is contained in:
parent
2737e94b24
commit
10d70ecd54
2 changed files with 168 additions and 6 deletions
160
src/FbTk/Menu.cc
160
src/FbTk/Menu.cc
|
@ -22,7 +22,7 @@
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
// DEALINGS IN THE SOFTWARE.
|
// 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
|
//use GNU extensions
|
||||||
#ifndef _GNU_SOURCE
|
#ifndef _GNU_SOURCE
|
||||||
|
@ -39,6 +39,8 @@
|
||||||
#include "Transparent.hh"
|
#include "Transparent.hh"
|
||||||
|
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -76,10 +78,12 @@ namespace FbTk {
|
||||||
static Menu *shown = 0;
|
static Menu *shown = 0;
|
||||||
|
|
||||||
unsigned char Menu::s_alpha = 255;
|
unsigned char Menu::s_alpha = 255;
|
||||||
|
Menu *Menu::s_focused = 0;
|
||||||
|
|
||||||
Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl):
|
Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl):
|
||||||
m_theme(tm),
|
m_theme(tm),
|
||||||
m_screen_num(screen_num),
|
m_screen_num(screen_num),
|
||||||
|
m_prev_focused_window(0),
|
||||||
m_image_ctrl(imgctrl),
|
m_image_ctrl(imgctrl),
|
||||||
m_display(FbTk::App::instance()->display()),
|
m_display(FbTk::App::instance()->display()),
|
||||||
m_parent(0),
|
m_parent(0),
|
||||||
|
@ -143,13 +147,15 @@ Menu::Menu(MenuTheme &tm, int screen_num, ImageControl &imgctrl):
|
||||||
XSetWindowAttributes attrib;
|
XSetWindowAttributes attrib;
|
||||||
attrib.override_redirect = True;
|
attrib.override_redirect = True;
|
||||||
attrib.event_mask = ButtonPressMask | ButtonReleaseMask |
|
attrib.event_mask = ButtonPressMask | ButtonReleaseMask |
|
||||||
ButtonMotionMask | KeyPressMask | ExposureMask;
|
ButtonMotionMask | KeyPressMask | ExposureMask | FocusChangeMask;
|
||||||
|
|
||||||
//create menu window
|
//create menu window
|
||||||
menu.window = XCreateWindow(m_display, RootWindow(m_display, screen_num),
|
menu.window = XCreateWindow(m_display, RootWindow(m_display, screen_num),
|
||||||
menu.x, menu.y, menu.width, menu.height,
|
menu.x, menu.y, menu.width, menu.height,
|
||||||
0, CopyFromParent,
|
0, CopyFromParent,
|
||||||
InputOutput, CopyFromParent, attrib_mask, &attrib);
|
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();
|
FbTk::EventManager &evm = *FbTk::EventManager::instance();
|
||||||
evm.add(*this, menu.window);
|
evm.add(*this, menu.window);
|
||||||
|
@ -199,7 +205,8 @@ Menu::~Menu() {
|
||||||
evm.remove(menu.title);
|
evm.remove(menu.title);
|
||||||
evm.remove(menu.frame);
|
evm.remove(menu.frame);
|
||||||
evm.remove(menu.window);
|
evm.remove(menu.window);
|
||||||
|
if (s_focused == this)
|
||||||
|
s_focused = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Menu::insert(const char *label, RefCount<Command> &cmd, int pos) {
|
int Menu::insert(const char *label, RefCount<Command> &cmd, int pos) {
|
||||||
|
@ -280,6 +287,80 @@ void Menu::lower() {
|
||||||
menu.window.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() {
|
void Menu::disableTitle() {
|
||||||
setTitleVisibility(false);
|
setTitleVisibility(false);
|
||||||
}
|
}
|
||||||
|
@ -486,8 +567,18 @@ void Menu::hide() {
|
||||||
p->internal_hide();
|
p->internal_hide();
|
||||||
} else
|
} else
|
||||||
internal_hide();
|
internal_hide();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::grabInputFocus() {
|
||||||
|
s_focused = this;
|
||||||
|
|
||||||
|
// grab input focus
|
||||||
|
menu.window.setInputFocus(RevertToPointerRoot, CurrentTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Menu::clearWindow() {
|
void Menu::clearWindow() {
|
||||||
menu.window.clear();
|
menu.window.clear();
|
||||||
menu.title.clear();
|
menu.title.clear();
|
||||||
|
@ -925,9 +1016,22 @@ bool Menu::isItemEnabled(unsigned int index) const {
|
||||||
return item->isEnabled();
|
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) {
|
void Menu::buttonPressEvent(XButtonEvent &be) {
|
||||||
|
grabInputFocus();
|
||||||
if (be.window == menu.frame && menu.item_h != 0 && menu.item_w != 0) {
|
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 sbl = (be.x / menu.item_w), i = (be.y / menu.item_h);
|
||||||
int w = (sbl * menu.persub) + i;
|
int w = (sbl * menu.persub) + i;
|
||||||
|
|
||||||
|
@ -1025,7 +1129,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
|
||||||
if ((i != which_press || sbl != which_sbl) &&
|
if ((i != which_press || sbl != which_sbl) &&
|
||||||
(w < static_cast<int>(menuitems.size()) && w >= 0)) {
|
(w < static_cast<int>(menuitems.size()) && w >= 0)) {
|
||||||
if (which_press != -1 && which_sbl != -1) {
|
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];
|
MenuItem *item = menuitems[p];
|
||||||
|
|
||||||
drawItem(p, false, true, true);
|
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() {
|
void Menu::reconfigure() {
|
||||||
m_need_update = true; // redraw items
|
m_need_update = true; // redraw items
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
// DEALINGS IN THE SOFTWARE.
|
// 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
|
#ifndef FBTK_MENU_HH
|
||||||
#define FBTK_MENU_HH
|
#define FBTK_MENU_HH
|
||||||
|
@ -85,6 +85,10 @@ public:
|
||||||
virtual void raise();
|
virtual void raise();
|
||||||
/// lower this window
|
/// lower this window
|
||||||
virtual void lower();
|
virtual void lower();
|
||||||
|
/// select next item
|
||||||
|
void nextItem();
|
||||||
|
/// select previous item
|
||||||
|
void prevItem();
|
||||||
|
|
||||||
void disableTitle();
|
void disableTitle();
|
||||||
void enableTitle();
|
void enableTitle();
|
||||||
|
@ -95,14 +99,17 @@ public:
|
||||||
@name event handlers
|
@name event handlers
|
||||||
*/
|
*/
|
||||||
//@{
|
//@{
|
||||||
|
void handleEvent(XEvent &event);
|
||||||
void buttonPressEvent(XButtonEvent &bp);
|
void buttonPressEvent(XButtonEvent &bp);
|
||||||
void buttonReleaseEvent(XButtonEvent &br);
|
void buttonReleaseEvent(XButtonEvent &br);
|
||||||
void motionNotifyEvent(XMotionEvent &mn);
|
void motionNotifyEvent(XMotionEvent &mn);
|
||||||
void enterNotifyEvent(XCrossingEvent &en);
|
void enterNotifyEvent(XCrossingEvent &en);
|
||||||
void leaveNotifyEvent(XCrossingEvent &ce);
|
void leaveNotifyEvent(XCrossingEvent &ce);
|
||||||
void exposeEvent(XExposeEvent &ee);
|
void exposeEvent(XExposeEvent &ee);
|
||||||
|
void keyPressEvent(XKeyEvent &ke);
|
||||||
//@}
|
//@}
|
||||||
|
/// get input focus
|
||||||
|
void grabInputFocus();
|
||||||
void reconfigure();
|
void reconfigure();
|
||||||
/// set label string
|
/// set label string
|
||||||
void setLabel(const char *labelstr);
|
void setLabel(const char *labelstr);
|
||||||
|
@ -142,6 +149,7 @@ public:
|
||||||
bool isItemSelected(unsigned int index) const;
|
bool isItemSelected(unsigned int index) const;
|
||||||
bool isItemEnabled(unsigned int index) const;
|
bool isItemEnabled(unsigned int index) const;
|
||||||
static unsigned char alpha() { return s_alpha; }
|
static unsigned char alpha() { return s_alpha; }
|
||||||
|
static Menu *focused() { return s_focused; }
|
||||||
/// @return menuitem at index
|
/// @return menuitem at index
|
||||||
inline const MenuItem *find(unsigned int index) const { return menuitems[index]; }
|
inline const MenuItem *find(unsigned int index) const { return menuitems[index]; }
|
||||||
inline MenuItem *find(unsigned int index) { return menuitems[index]; }
|
inline MenuItem *find(unsigned int index) { return menuitems[index]; }
|
||||||
|
@ -170,6 +178,7 @@ private:
|
||||||
const MenuTheme &m_theme;
|
const MenuTheme &m_theme;
|
||||||
Display *m_display;
|
Display *m_display;
|
||||||
const int m_screen_num;
|
const int m_screen_num;
|
||||||
|
Window m_prev_focused_window;
|
||||||
Menu *m_parent;
|
Menu *m_parent;
|
||||||
ImageControl &m_image_ctrl;
|
ImageControl &m_image_ctrl;
|
||||||
Menuitems menuitems;
|
Menuitems menuitems;
|
||||||
|
@ -206,6 +215,7 @@ private:
|
||||||
std::auto_ptr<Transparent> m_trans;
|
std::auto_ptr<Transparent> m_trans;
|
||||||
Drawable m_root_pm;
|
Drawable m_root_pm;
|
||||||
static unsigned char s_alpha;
|
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;
|
FbPixmap m_frame_pm;
|
||||||
bool m_need_update;
|
bool m_need_update;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue