Improved mouse and keyboard handling in sub-menus

This commit is contained in:
Markus Gans 2015-11-24 23:40:41 +01:00
parent 53ada3664c
commit 692f8248e1
8 changed files with 188 additions and 92 deletions

View File

@ -1,3 +1,6 @@
2015-11-24 Markus Gans <guru.mail@muenster.de>
* Improved mouse and keyboard handling in sub-menus
2015-11-22 Markus Gans <guru.mail@muenster.de> 2015-11-22 Markus Gans <guru.mail@muenster.de>
* Add sub-menu support * Add sub-menu support

View File

@ -356,7 +356,9 @@ void FApplication::processKeyboardEvent()
FKeyEvent k_press_ev (KeyPress_Event, key); FKeyEvent k_press_ev (KeyPress_Event, key);
sendEvent (widget, &k_press_ev); sendEvent (widget, &k_press_ev);
if ( ! k_press_ev.isAccepted() && ! k_down_ev.isAccepted() ) if ( ! open_menu
&& ! k_press_ev.isAccepted()
&& ! k_down_ev.isAccepted() )
{ {
// keyboard accelerator // keyboard accelerator
FWidget* window = static_cast<FWidget*>(active_window); FWidget* window = static_cast<FWidget*>(active_window);

View File

@ -242,15 +242,11 @@ void FMenu::openSubMenu (FMenu* sub_menu)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FMenu::hideSubMenus() void FMenu::hideSubMenus()
{ {
if ( ! hasSelectedItem() )
return;
// hide all sub-menus // hide all sub-menus
if ( getSelectedItem()->hasMenu() ) if ( open_sub_menu )
{ {
FMenu* m = getSelectedItem()->getMenu(); open_sub_menu->hideSubMenus();
m->hideSubMenus(); open_sub_menu->hide();
m->hide();
open_sub_menu = 0; open_sub_menu = 0;
} }
unselectItem(); unselectItem();
@ -295,6 +291,26 @@ bool FMenu::containsMenuStructure (int x, int y) const
return false; return false;
} }
//----------------------------------------------------------------------
FMenu* FMenu::superMenuAt (int x, int y) const
{
// Check mouse click position for super menu
if ( getGeometryGlobal().contains(x,y) )
return 0;
FWidget* super = getSuperMenu();
if ( super && isMenu(super) )
{
if ( super->getGeometryGlobal().contains(x,y) )
return dynamic_cast<FMenu*>(super);
else
{
FMenu* smenu = dynamic_cast<FMenu*>(getSuperMenu());
return smenu->superMenuAt(x,y);
}
}
return 0;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
bool FMenu::selectNextItem() bool FMenu::selectNextItem()
{ {
@ -422,8 +438,11 @@ bool FMenu::hotkeyMenu (FKeyEvent*& ev)
if ( found ) if ( found )
{ {
unselectItem(); unselectItem();
hideSubMenus();
hide(); hide();
hideSuperMenus(); hideSuperMenus();
updateTerminal();
flush_out();
ev->accept(); ev->accept();
(*iter)->processClicked(); (*iter)->processClicked();
return true; return true;
@ -757,10 +776,10 @@ void FMenu::onKeyPress (FKeyEvent* ev)
return; return;
// looking for menu bar hotkey // looking for menu bar hotkey
FWidget* smenu = getSuperMenu(); FWidget* menubar = menuBar();
if ( smenu && isMenuBar(smenu)) if ( menubar )
{ {
FMenuBar* mbar = reinterpret_cast<FMenuBar*>(smenu); FMenuBar* mbar = reinterpret_cast<FMenuBar*>(menubar);
if ( mbar->hotkeyMenu(ev) ) if ( mbar->hotkeyMenu(ev) )
return; return;
} }
@ -783,17 +802,14 @@ void FMenu::onKeyPress (FKeyEvent* ev)
sel_item->processClicked(); sel_item->processClicked();
} }
} }
ev->accept();
break; break;
case fc::Fkey_up: case fc::Fkey_up:
selectPrevItem(); selectPrevItem();
ev->accept();
break; break;
case fc::Fkey_down: case fc::Fkey_down:
selectNextItem(); selectNextItem();
ev->accept();
break; break;
case fc::Fkey_left: case fc::Fkey_left:
@ -811,19 +827,14 @@ void FMenu::onKeyPress (FKeyEvent* ev)
} }
else else
keypressMenuBar(ev); // select previous menu keypressMenuBar(ev); // select previous menu
ev->accept();
break; break;
case fc::Fkey_right: case fc::Fkey_right:
if ( hasSelectedItem() && getSelectedItem()->hasMenu() ) if ( hasSelectedItem() && getSelectedItem()->hasMenu() )
{ {
FMenu* sub_menu = getSelectedItem()->getMenu(); FMenu* sub_menu = getSelectedItem()->getMenu();
if ( ! sub_menu->isVisible() ) if ( ! sub_menu->isVisible() )
{
openSubMenu (sub_menu); openSubMenu (sub_menu);
ev->accept();
}
else else
keypressMenuBar(ev); // select next menu keypressMenuBar(ev); // select next menu
} }
@ -853,12 +864,14 @@ void FMenu::onKeyPress (FKeyEvent* ev)
statusBar()->drawMessage(); statusBar()->drawMessage();
updateTerminal(); updateTerminal();
flush_out(); flush_out();
ev->accept();
break; break;
default: default:
break; break;
} }
// always accept key event -> no forwarding to the parent widget
ev->accept();
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -878,6 +891,7 @@ void FMenu::onMouseDown (FMouseEvent* ev)
if ( ! itemlist.empty() ) if ( ! itemlist.empty() )
{ {
std::vector<FMenuItem*>::const_iterator iter, end; std::vector<FMenuItem*>::const_iterator iter, end;
FMenu* show_sub_menu = 0;
bool focus_changed = false; bool focus_changed = false;
FPoint mouse_pos; FPoint mouse_pos;
@ -898,15 +912,37 @@ void FMenu::onMouseDown (FMouseEvent* ev)
if ( mouse_x >= x1 if ( mouse_x >= x1
&& mouse_x <= x2 && mouse_x <= x2
&& mouse_y == y && mouse_y == y )
&& ! (*iter)->isSelected() )
{ {
// Mouse pointer over item // Mouse pointer over item
if ( hasSelectedItem() )
{
FMenuItem* sel_item = getSelectedItem();
if ( sel_item
&& sel_item->hasMenu()
&& sel_item->getMenu() == open_sub_menu )
{
if ( sel_item != *iter )
hideSubMenus();
else
{
open_sub_menu->unselectItem();
raiseWindow (open_sub_menu);
open_sub_menu->redraw();
sel_item->setFocus();
if ( statusBar() )
statusBar()->drawMessage();
updateTerminal();
flush_out();
}
}
}
if ( ! (*iter)->isSelected() )
{
unselectItem();
FWidget* focused_widget = getFocusWidget(); FWidget* focused_widget = getFocusWidget();
FFocusEvent out (FocusOut_Event); FFocusEvent out (FocusOut_Event);
FApplication::queueEvent(focused_widget, &out); FApplication::queueEvent(focused_widget, &out);
if ( hasSelectedItem() )
unselectItem();
(*iter)->setSelected(); (*iter)->setSelected();
setSelectedItem(*iter); setSelectedItem(*iter);
(*iter)->setFocus(); (*iter)->setFocus();
@ -914,12 +950,32 @@ void FMenu::onMouseDown (FMouseEvent* ev)
focused_widget->redraw(); focused_widget->redraw();
if ( statusBar() ) if ( statusBar() )
statusBar()->drawMessage(); statusBar()->drawMessage();
if ( (*iter)->hasMenu() )
{
FMenu* sub_menu = (*iter)->getMenu();
if ( ! sub_menu->isVisible() )
show_sub_menu = sub_menu;
}
focus_changed = true; focus_changed = true;
} }
}
++iter; ++iter;
} }
if ( focus_changed ) if ( focus_changed )
redraw(); redraw();
if ( show_sub_menu )
{
// open sub menu
show_sub_menu->setVisible();
show_sub_menu->show();
open_sub_menu = show_sub_menu;
raiseWindow (show_sub_menu);
show_sub_menu->redraw();
updateTerminal();
flush_out();
}
} }
} }
@ -960,12 +1016,46 @@ void FMenu::onMouseUp (FMouseEvent* ev)
&& mouse_y == y ) && mouse_y == y )
{ {
// Mouse pointer over item // Mouse pointer over item
if ( (*iter)->hasMenu() )
{
FMenu* sub_menu = (*iter)->getMenu();
if ( ! sub_menu->isVisible() )
openSubMenu (sub_menu);
else if ( open_sub_menu )
{
if ( open_sub_menu->hasSelectedItem() )
{
FMenuItem* sel_item = getSelectedItem();
hideSubMenus();
sel_item->setFocus();
redraw();
if ( statusBar() )
statusBar()->drawMessage();
updateTerminal();
flush_out();
}
else
{
open_sub_menu->selectFirstItem();
open_sub_menu->getSelectedItem()->setFocus();
open_sub_menu->redraw();
if ( statusBar() )
statusBar()->drawMessage();
updateTerminal();
flush_out();
}
}
return;
}
else
{
unselectItem(); unselectItem();
hide(); hide();
hideSuperMenus(); hideSuperMenus();
(*iter)->processClicked(); (*iter)->processClicked();
} }
} }
}
++iter; ++iter;
} }
// Click on a non-FMenuItem (border or separator line) // Click on a non-FMenuItem (border or separator line)
@ -988,10 +1078,12 @@ void FMenu::onMouseMove (FMouseEvent* ev)
if ( mouse_down && ! itemlist.empty() ) if ( mouse_down && ! itemlist.empty() )
{ {
std::vector<FMenuItem*>::const_iterator iter, end; std::vector<FMenuItem*>::const_iterator iter, end;
FMenu* smenu = 0;
bool focus_changed = false; bool focus_changed = false;
bool mouse_over_menu = false; bool mouse_over_menu = false;
bool mouse_over_submenu = false; bool mouse_over_submenu = false;
bool mouse_over_supermenu = false; bool mouse_over_supermenu = false;
bool mouse_over_menubar = false;
bool hide_sub_menu = false; bool hide_sub_menu = false;
FMenu* show_sub_menu = 0; FMenu* show_sub_menu = 0;
FPoint mouse_pos; FPoint mouse_pos;
@ -1013,11 +1105,18 @@ void FMenu::onMouseMove (FMouseEvent* ev)
if ( isSubMenu() ) if ( isSubMenu() )
{ {
const FRect& supermenu_geometry = getSuperMenu()->getGeometryGlobal(); smenu = superMenuAt (ev->getGlobalPos());
if ( supermenu_geometry.contains(ev->getGlobalPos()) ) if ( smenu )
mouse_over_supermenu = true; mouse_over_supermenu = true;
} }
if ( menuBar()
&& isMenuBar(menuBar())
&& menuBar()->getGeometryGlobal().contains(ev->getGlobalPos()) )
{
mouse_over_menubar = true;
}
while ( iter != end ) while ( iter != end )
{ {
int x1, x2, y, mouse_x, mouse_y; int x1, x2, y, mouse_x, mouse_y;
@ -1089,7 +1188,6 @@ void FMenu::onMouseMove (FMouseEvent* ev)
else if ( ! mouse_over_menu && mouse_over_supermenu ) else if ( ! mouse_over_menu && mouse_over_supermenu )
{ {
// Mouse event handover to super-menu // Mouse event handover to super-menu
FMenu* smenu = dynamic_cast<FMenu*>(getSuperMenu());
const FPoint& g = ev->getGlobalPos(); const FPoint& g = ev->getGlobalPos();
const FPoint& p = smenu->globalToLocalPos(g); const FPoint& p = smenu->globalToLocalPos(g);
int b = ev->getButton(); int b = ev->getButton();
@ -1098,6 +1196,20 @@ void FMenu::onMouseMove (FMouseEvent* ev)
setClickedWidget(smenu); setClickedWidget(smenu);
smenu->onMouseMove(ev); smenu->onMouseMove(ev);
} }
else if ( mouse_over_menubar )
{
// Mouse event handover to the menu bar
FWidget* menubar = menuBar();
const FPoint& g = ev->getGlobalPos();
const FPoint& p = menubar->globalToLocalPos(g);
int b = ev->getButton();
ev = new FMouseEvent (MouseMove_Event, p, g, b);
setClickedWidget(menubar);
FMenuBar* mbar = reinterpret_cast<FMenuBar*>(menubar);
mbar->mouse_down = true;
mbar->onMouseMove(ev);
delete ev;
}
else if ( ! hasSelectedItem() && statusBar() && mouse_over_menu ) else if ( ! hasSelectedItem() && statusBar() && mouse_over_menu )
{ {
// Mouse is over border or separator // Mouse is over border or separator
@ -1112,23 +1224,6 @@ void FMenu::onMouseMove (FMouseEvent* ev)
hide_sub_menu = true; hide_sub_menu = true;
} }
// Mouse event handover to the menu bar
FWidget* menubar = getSuperMenu();
if ( menubar
&& isMenuBar(menubar)
&& menubar->getGeometryGlobal().contains(ev->getGlobalPos()) )
{
const FPoint& g = ev->getGlobalPos();
const FPoint& p = menubar->globalToLocalPos(g);
int b = ev->getButton();
ev = new FMouseEvent (MouseMove_Event, p, g, b);
setClickedWidget(menubar);
FMenuBar* mbar = reinterpret_cast<FMenuBar*>(menubar);
mbar->mouse_down = true;
mbar->onMouseMove(ev);
delete ev;
}
if ( focus_changed ) if ( focus_changed )
redraw(); redraw();
@ -1213,12 +1308,6 @@ void FMenu::setStatusbarMessage(FString msg)
item->setStatusbarMessage(msg); item->setStatusbarMessage(msg);
} }
//----------------------------------------------------------------------
void FMenu::cb_menuitem_activated (FWidget*, void*)
{
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FMenu::cb_menuitem_toggled (FWidget* widget, void*) void FMenu::cb_menuitem_toggled (FWidget* widget, void*)
{ {

View File

@ -69,6 +69,8 @@ class FMenu : public FWindow, public FMenuList
void hideSuperMenus(); void hideSuperMenus();
bool containsMenuStructure (const FPoint&) const; bool containsMenuStructure (const FPoint&) const;
bool containsMenuStructure (int, int) const; bool containsMenuStructure (int, int) const;
FMenu* superMenuAt (const FPoint&) const;
FMenu* superMenuAt (int, int) const;
bool selectNextItem(); bool selectNextItem();
bool selectPrevItem(); bool selectPrevItem();
void keypressMenuBar (FKeyEvent*&); void keypressMenuBar (FKeyEvent*&);
@ -120,7 +122,6 @@ class FMenu : public FWindow, public FMenuList
void setText (FString&); void setText (FString&);
void setText (const std::string&); void setText (const std::string&);
void setText (const char*); void setText (const char*);
void cb_menuitem_activated (FWidget*, void*);
void cb_menuitem_toggled (FWidget*, void*); void cb_menuitem_toggled (FWidget*, void*);
private: private:
@ -146,6 +147,10 @@ inline void FMenu::setSuperMenu (FWidget* smenu)
inline bool FMenu::containsMenuStructure (const FPoint& p) const inline bool FMenu::containsMenuStructure (const FPoint& p) const
{ return containsMenuStructure (p.getX(), p.getY()); } { return containsMenuStructure (p.getX(), p.getY()); }
//----------------------------------------------------------------------
inline FMenu* FMenu::superMenuAt (const FPoint& p) const
{ return superMenuAt (p.getX(), p.getY()); }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
inline const char* FMenu::getClassName() const inline const char* FMenu::getClassName() const
{ return "FMenu"; } { return "FMenu"; }

View File

@ -848,5 +848,6 @@ void FMenuBar::cb_item_deactivated (FWidget* widget, void*)
{ {
FMenu* menu = menuitem->getMenu(); FMenu* menu = menuitem->getMenu();
menu->hide(); menu->hide();
menu->hideSubMenus();
} }
} }

View File

@ -191,12 +191,6 @@ void FMenuItem::init (FWidget* parent)
FMenu* menu_ptr = dynamic_cast<FMenu*>(parent); FMenu* menu_ptr = dynamic_cast<FMenu*>(parent);
if ( menu_ptr ) if ( menu_ptr )
menu_ptr->menu_dimension(); menu_ptr->menu_dimension();
this->addCallback
(
"activate",
_METHOD_CALLBACK (parent, &FMenu::cb_menuitem_activated)
);
} }
} }
if ( hasFocus() ) if ( hasFocus() )
@ -656,28 +650,30 @@ void FMenuItem::unsetSelected()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FMenuItem::openMenu() void FMenuItem::openMenu()
{ {
FMenu* submenu; FMenu* menu;
FMenu* open_menu; FMenu* open_menu;
if ( hasMenu() ) if ( hasMenu() )
{ {
submenu = getMenu(); menu = getMenu();
if ( menu->isVisible() )
return;
if ( ! submenu->isVisible() )
{
open_menu = static_cast<FMenu*>(getOpenMenu()); open_menu = static_cast<FMenu*>(getOpenMenu());
if ( open_menu && open_menu != submenu ) if ( open_menu && open_menu != menu )
{
open_menu->hide(); open_menu->hide();
setOpenMenu(submenu); open_menu->hideSubMenus();
}
setOpenMenu(menu);
submenu->setVisible(); menu->setVisible();
submenu->show(); menu->show();
submenu->raiseWindow(submenu); menu->raiseWindow(menu);
submenu->redraw(); menu->redraw();
updateTerminal(); updateTerminal();
flush_out(); flush_out();
} }
}
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@ -94,7 +94,6 @@ class FMenuItem : public FWidget
void onAccel (FAccelEvent*); void onAccel (FAccelEvent*);
void onFocusIn (FFocusEvent*); void onFocusIn (FFocusEvent*);
void onFocusOut (FFocusEvent*); void onFocusOut (FFocusEvent*);
FString getText() const;
// make every setEnable from FWidget available // make every setEnable from FWidget available
using FWidget::setEnable; using FWidget::setEnable;
bool setEnable(bool); bool setEnable(bool);
@ -117,6 +116,7 @@ class FMenuItem : public FWidget
bool hasMenu() const; bool hasMenu() const;
void openMenu(); void openMenu();
uInt getTextLength() const; uInt getTextLength() const;
FString getText() const;
void setText (FString&); void setText (FString&);
void setText (const std::string&); void setText (const std::string&);
void setText (const char*); void setText (const char*);
@ -142,10 +142,6 @@ inline FWidget* FMenuItem::getSuperMenu() const
inline void FMenuItem::setSuperMenu (FWidget* smenu) inline void FMenuItem::setSuperMenu (FWidget* smenu)
{ super_menu = smenu; } { super_menu = smenu; }
//----------------------------------------------------------------------
inline FString FMenuItem::getText() const
{ return text; }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
inline bool FMenuItem::setFocus() inline bool FMenuItem::setFocus()
{ return setFocus(true); } { return setFocus(true); }
@ -212,4 +208,8 @@ inline bool FMenuItem::hasMenu() const
inline uInt FMenuItem::getTextLength() const inline uInt FMenuItem::getTextLength() const
{ return text_length; } { return text_length; }
//----------------------------------------------------------------------
inline FString FMenuItem::getText() const
{ return text; }
#endif // _FMENUITEM_H #endif // _FMENUITEM_H