Refactoring of the FMenuBar mouse event handler

This commit is contained in:
Markus Gans 2017-12-31 03:25:50 +01:00
parent 3b90af9efb
commit 2e64c0da32
3 changed files with 305 additions and 258 deletions

View File

@ -1,5 +1,6 @@
2017-12-30 Markus Gans <guru.mail@muenster.de>
2017-12-31 Markus Gans <guru.mail@muenster.de>
* Refactoring of the FListBox mouse event handler
* Refactoring of the FMenuBar mouse event handler
* Replace the switch-case in the calculator example by an STL map
with method pointers

View File

@ -134,6 +134,14 @@ class FMenuBar : public FWindow, public FMenuList
void drawLeadingSpace (int&);
void drawTrailingSpace (int&);
void adjustItems();
bool activateMenu (FMenuItem*);
bool clickItem (FMenuItem*);
void unselectMenuItem (FMenuItem*);
void selectMenuItem (FMenuItem*);
void mouseDownOverList (FMouseEvent*);
void mouseUpOverList (FMouseEvent*);
void mouseMoveOverList (FMouseEvent*);
void passEventToMenu (FMouseEvent*&);
void leaveMenuBar();
// Friend classes
@ -143,6 +151,7 @@ class FMenuBar : public FWindow, public FMenuList
// Data Members
bool mouse_down;
bool drop_down;
bool focus_changed;
int screenWidth;
};
#pragma pack(pop)

View File

@ -37,6 +37,7 @@ FMenuBar::FMenuBar(FWidget* parent)
: FWindow(parent)
, mouse_down(false)
, drop_down(false)
, focus_changed(false)
, screenWidth(80)
{
init();
@ -187,79 +188,8 @@ void FMenuBar::onMouseDown (FMouseEvent* ev)
if ( ! isWindowActive() )
setActiveWindow(this);
if ( ! item_list.empty() )
{
std::vector<FMenuItem*>::const_iterator iter, last;
int mouse_x, mouse_y;
bool focus_changed = false;
iter = item_list.begin();
last = item_list.end();
mouse_x = ev->getX();
mouse_y = ev->getY();
while ( iter != last )
{
int x1, x2;
x1 = (*iter)->getX();
x2 = (*iter)->getX() + (*iter)->getWidth();
if ( mouse_y == 1 )
{
if ( mouse_x >= x1 && mouse_x < x2 )
{
// Mouse pointer over item
if ( (*iter)->isEnabled() && ! (*iter)->isSelected() )
{
FWidget* focused_widget = getFocusWidget();
FFocusEvent out (fc::FocusOut_Event);
FApplication::queueEvent(focused_widget, &out);
(*iter)->setSelected();
(*iter)->setFocus();
if ( focused_widget && ! focused_widget->isWindowWidget() )
focused_widget->redraw();
(*iter)->openMenu();
setSelectedItem(*iter);
focus_changed = true;
if ( (*iter)->hasMenu() )
{
FMenu* menu = (*iter)->getMenu();
if ( menu->hasSelectedItem() )
{
menu->unselectItem();
menu->redraw();
drop_down = true;
}
}
}
}
else if ( (*iter)->isEnabled() && (*iter)->isSelected() )
{
(*iter)->unsetSelected();
if ( getSelectedItem() == *iter )
setSelectedItem(0);
focus_changed = true;
}
}
++iter;
}
if ( getStatusBar() )
getStatusBar()->drawMessage();
if ( focus_changed )
{
redraw();
updateTerminal();
}
}
// Handle menu entries
mouseDownOverList(ev);
}
//----------------------------------------------------------------------
@ -272,78 +202,8 @@ void FMenuBar::onMouseUp (FMouseEvent* ev)
{
mouse_down = false;
if ( ! item_list.empty() )
{
int mouse_x, mouse_y;
std::vector<FMenuItem*>::const_iterator iter, last;
iter = item_list.begin();
last = item_list.end();
mouse_x = ev->getX();
mouse_y = ev->getY();
while ( iter != last )
{
int x1, x2;
x1 = (*iter)->getX();
x2 = (*iter)->getX() + (*iter)->getWidth();
if ( mouse_y == 1 && (*iter)->isEnabled() && (*iter)->isSelected() )
{
if ( mouse_x >= x1 && mouse_x < x2 )
{
// Mouse pointer over item
if ( (*iter)->hasMenu() )
{
FMenu* menu = (*iter)->getMenu();
if ( ! menu->hasSelectedItem() )
{
FMenuItem* first_item;
menu->selectFirstItem();
first_item = menu->getSelectedItem();
if ( first_item )
first_item->setFocus();
if ( getStatusBar() )
getStatusBar()->drawMessage();
redraw();
menu->redraw();
drop_down = true;
}
}
else
{
(*iter)->unsetSelected();
if ( getSelectedItem() == *iter )
{
setSelectedItem(0);
leaveMenuBar();
drop_down = false;
(*iter)->processClicked();
return;
}
}
}
else
{
(*iter)->unsetSelected();
if ( getSelectedItem() == *iter )
setSelectedItem(0);
redraw();
}
}
++iter;
}
if ( ! hasSelectedItem() )
leaveMenuBar();
}
// Handle menu entries
mouseUpOverList(ev);
}
}
@ -356,118 +216,9 @@ void FMenuBar::onMouseMove (FMouseEvent* ev)
if ( ! isWindowActive() )
setActiveWindow(this);
if ( mouse_down && ! item_list.empty() )
{
std::vector<FMenuItem*>::const_iterator iter, last;
int mouse_x, mouse_y;
bool mouse_over_menubar = false;
bool focus_changed = false;
iter = item_list.begin();
last = item_list.end();
mouse_x = ev->getX();
mouse_y = ev->getY();
if ( getTermGeometry().contains(ev->getTermPos()) )
mouse_over_menubar = true;
while ( iter != last )
{
int x1, x2;
x1 = (*iter)->getX();
x2 = (*iter)->getX() + (*iter)->getWidth();
if ( mouse_x >= x1
&& mouse_x < x2
&& mouse_y == 1 )
{
// Mouse pointer over item
if ( (*iter)->isEnabled() && ! (*iter)->isSelected() )
{
FWidget* focused_widget = getFocusWidget();
FFocusEvent out (fc::FocusOut_Event);
FApplication::queueEvent(focused_widget, &out);
(*iter)->setSelected();
(*iter)->setFocus();
if ( focused_widget && ! focused_widget->isWindowWidget() )
focused_widget->redraw();
(*iter)->openMenu();
setSelectedItem(*iter);
focus_changed = true;
if ( (*iter)->hasMenu() )
{
FMenu* menu = (*iter)->getMenu();
if ( menu->hasSelectedItem() )
{
menu->unselectItem();
menu->redraw();
drop_down = true;
}
}
}
else if ( getStatusBar() )
getStatusBar()->clearMessage();
}
else
{
if ( mouse_over_menubar
&& (*iter)->isEnabled()
&& (*iter)->isSelected() )
{
// Unselect selected item without mouse focus
(*iter)->unsetSelected();
if ( getSelectedItem() == *iter )
setSelectedItem(0);
focus_changed = true;
drop_down = false;
}
else if ( hasSelectedItem() && getSelectedItem()->hasMenu() )
{
// Mouse event handover to the menu
FMenu* menu = getSelectedItem()->getMenu();
const FRect& menu_geometry = menu->getTermGeometry();
if ( menu->getCount() > 0
&& menu_geometry.contains(ev->getTermPos()) )
{
const FPoint& t = ev->getTermPos();
const FPoint& p = menu->termToWidgetPos(t);
int b = ev->getButton();
try
{
FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b);
menu->mouse_down = true;
setClickedWidget(menu);
menu->onMouseMove(_ev);
delete _ev;
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc "
<< ex.what() << std::endl;
}
}
}
}
++iter;
}
if ( getStatusBar() )
getStatusBar()->drawMessage();
if ( focus_changed )
{
redraw();
updateTerminal();
}
}
// Handle menu entries
if ( mouse_down )
mouseMoveOverList(ev);
}
//----------------------------------------------------------------------
@ -1009,6 +760,292 @@ void FMenuBar::adjustItems()
}
}
//----------------------------------------------------------------------
void FMenuBar::selectMenuItem (FMenuItem* item)
{
if ( ! item->isEnabled() || item->isSelected() )
return;
FWidget* focused_widget = getFocusWidget();
FFocusEvent out (fc::FocusOut_Event);
FApplication::queueEvent(focused_widget, &out);
item->setSelected();
item->setFocus();
if ( focused_widget && ! focused_widget->isWindowWidget() )
focused_widget->redraw();
item->openMenu();
setSelectedItem(item);
focus_changed = true;
if ( item->hasMenu() )
{
FMenu* menu = item->getMenu();
if ( menu->hasSelectedItem() )
{
menu->unselectItem();
menu->redraw();
drop_down = true;
}
}
}
//----------------------------------------------------------------------
bool FMenuBar::activateMenu (FMenuItem* item)
{
if ( ! item->hasMenu() )
return false;
FMenu* menu = item->getMenu();
if ( ! menu->hasSelectedItem() )
{
FMenuItem* first_item;
menu->selectFirstItem();
first_item = menu->getSelectedItem();
if ( first_item )
first_item->setFocus();
if ( getStatusBar() )
getStatusBar()->drawMessage();
redraw();
menu->redraw();
drop_down = true;
}
return true;
}
//----------------------------------------------------------------------
bool FMenuBar::clickItem (FMenuItem* item)
{
if ( item->hasMenu() )
return false;
item->unsetSelected();
if ( getSelectedItem() == item )
{
setSelectedItem(0);
leaveMenuBar();
drop_down = false;
item->processClicked();
}
return true;
}
//----------------------------------------------------------------------
void FMenuBar::unselectMenuItem (FMenuItem* item)
{
if ( ! item->isEnabled() || ! item->isSelected() )
return;
item->unsetSelected();
focus_changed = true;
drop_down = false;
if ( getSelectedItem() == item )
setSelectedItem(0);
}
//----------------------------------------------------------------------
void FMenuBar::mouseDownOverList (FMouseEvent* ev)
{
if ( item_list.empty() )
return;
std::vector<FMenuItem*>::const_iterator iter, last;
int mouse_x, mouse_y;
focus_changed = false;
iter = item_list.begin();
last = item_list.end();
mouse_x = ev->getX();
mouse_y = ev->getY();
while ( iter != last )
{
int x1, x2;
x1 = (*iter)->getX();
x2 = (*iter)->getX() + (*iter)->getWidth();
if ( mouse_y == 1 )
{
if ( mouse_x >= x1 && mouse_x < x2 )
{
// Mouse pointer over item
selectMenuItem (*iter);
}
else
{
unselectMenuItem (*iter);
}
}
++iter;
}
if ( getStatusBar() )
{
if ( ! hasSelectedItem() )
getStatusBar()->clearMessage();
getStatusBar()->drawMessage();
}
if ( focus_changed )
{
redraw();
updateTerminal();
}
}
//----------------------------------------------------------------------
void FMenuBar::mouseUpOverList (FMouseEvent* ev)
{
if ( item_list.empty() )
return;
int mouse_x, mouse_y;
std::vector<FMenuItem*>::const_iterator iter, last;
iter = item_list.begin();
last = item_list.end();
mouse_x = ev->getX();
mouse_y = ev->getY();
while ( iter != last )
{
int x1, x2;
x1 = (*iter)->getX();
x2 = (*iter)->getX() + (*iter)->getWidth();
if ( mouse_y == 1
&& mouse_x >= x1
&& mouse_x < x2
&& (*iter)->isEnabled()
&& (*iter)->isSelected() )
{
// Mouse pointer over item
if ( ! activateMenu(*iter) )
{
if ( clickItem(*iter) )
return;
}
}
else
{
unselectMenuItem(*iter);
redraw();
}
++iter;
}
if ( ! hasSelectedItem() )
leaveMenuBar();
}
//----------------------------------------------------------------------
void FMenuBar::mouseMoveOverList (FMouseEvent* ev)
{
if ( item_list.empty() )
return;
std::vector<FMenuItem*>::const_iterator iter, last;
int mouse_x, mouse_y;
bool mouse_over_menubar = false;
focus_changed = false;
iter = item_list.begin();
last = item_list.end();
mouse_x = ev->getX();
mouse_y = ev->getY();
if ( getTermGeometry().contains(ev->getTermPos()) )
mouse_over_menubar = true;
while ( iter != last )
{
int x1, x2;
x1 = (*iter)->getX();
x2 = (*iter)->getX() + (*iter)->getWidth();
if ( mouse_x >= x1
&& mouse_x < x2
&& mouse_y == 1 )
{
// Mouse pointer over item
selectMenuItem(*iter);
}
else
{
if ( mouse_over_menubar )
{
// Unselect selected item without mouse focus
unselectMenuItem(*iter);
}
else
{
// Event handover to the menu
passEventToMenu(ev);
}
}
++iter;
}
if ( getStatusBar() )
{
if ( ! hasSelectedItem() )
getStatusBar()->clearMessage();
getStatusBar()->drawMessage();
}
if ( focus_changed )
{
redraw();
updateTerminal();
}
}
//----------------------------------------------------------------------
void FMenuBar::passEventToMenu (FMouseEvent*& ev)
{
if ( ! hasSelectedItem() || ! getSelectedItem()->hasMenu() )
return;
// Mouse event handover to the menu
FMenu* menu = getSelectedItem()->getMenu();
const FRect& menu_geometry = menu->getTermGeometry();
if ( menu->getCount() > 0
&& menu_geometry.contains(ev->getTermPos()) )
{
const FPoint& t = ev->getTermPos();
const FPoint& p = menu->termToWidgetPos(t);
int b = ev->getButton();
try
{
FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b);
menu->mouse_down = true;
setClickedWidget(menu);
menu->onMouseMove(_ev);
delete _ev;
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc "
<< ex.what() << std::endl;
}
}
}
//----------------------------------------------------------------------
void FMenuBar::leaveMenuBar()
{