From 2e64c0da32a27cb997d5083c302a553f6e58fb8c Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Sun, 31 Dec 2017 03:25:50 +0100 Subject: [PATCH] Refactoring of the FMenuBar mouse event handler --- ChangeLog | 3 +- include/final/fmenubar.h | 9 + src/fmenubar.cpp | 551 +++++++++++++++++++++------------------ 3 files changed, 305 insertions(+), 258 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0a4ab9cf..d9a50829 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ -2017-12-30 Markus Gans +2017-12-31 Markus Gans * 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 diff --git a/include/final/fmenubar.h b/include/final/fmenubar.h index 6c9a4759..7acc5254 100644 --- a/include/final/fmenubar.h +++ b/include/final/fmenubar.h @@ -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) diff --git a/src/fmenubar.cpp b/src/fmenubar.cpp index 02c51c9a..5724381e 100644 --- a/src/fmenubar.cpp +++ b/src/fmenubar.cpp @@ -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::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::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::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::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::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::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() {