From fd75f5af42c335ff759ff03784ae1c9cee28fa8b Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Sun, 10 Dec 2017 15:36:02 +0100 Subject: [PATCH] Refactoring of the FMenu mouse event handler --- ChangeLog | 3 + examples/calculator.cpp | 3 +- examples/ui.cpp | 23 + include/final/fapplication.h | 6 +- include/final/fmenu.h | 33 +- include/final/fterm.h | 27 +- src/fapplication.cpp | 3 +- src/flistbox.cpp | 16 +- src/fmenu.cpp | 885 +++++++++++++++++++---------------- src/fterm.cpp | 5 +- src/fvterm.cpp | 2 +- 11 files changed, 576 insertions(+), 430 deletions(-) diff --git a/ChangeLog b/ChangeLog index 11138db9..0f46851c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2017-12-10 Markus Gans + * Refactoring of the FMenu mouse event handler + 2017-12-08 Markus Gans * More individual arithmetic operations methods in the implementation of the calculator example diff --git a/examples/calculator.cpp b/examples/calculator.cpp index 475812ad..281d4360 100644 --- a/examples/calculator.cpp +++ b/examples/calculator.cpp @@ -1037,7 +1037,8 @@ void Calc::onKeyPress (FKeyEvent* ev) else input = input.left(input.getLength() - 1); - a = lDouble(std::atof(input.c_str())); + lDouble& x = getValue(); + x = lDouble(std::atof(input.c_str())); drawDispay(); updateTerminal(); } diff --git a/examples/ui.cpp b/examples/ui.cpp index d33ec68a..ea0b7d30 100644 --- a/examples/ui.cpp +++ b/examples/ui.cpp @@ -333,6 +333,29 @@ class MyDialog : public FDialog //---------------------------------------------------------------------- MyDialog::MyDialog (FWidget* parent) : FDialog(parent) + , Open() + , Quit() + , File1() + , File2() + , File3() + , Cut() + , Copy() + , Paste() + , Clear() + , Env() + , Drive() + , Help() + , key_F1() + , key_F2() + , key_F3() + , MyButton1() + , MyButton2() + , MyButton3() + , MyButton4() + , MyButton5() + , MyButton6() + , radio1() + , tagged_count() , myLineEdit() , myList() , clipboard() diff --git a/include/final/fapplication.h b/include/final/fapplication.h index 562c8b3b..a58df829 100644 --- a/include/final/fapplication.h +++ b/include/final/fapplication.h @@ -111,7 +111,11 @@ class FApplication : public FWidget static bool eventInQueue(); static bool removeQueuedEvent (const FObject*); static FWidget* processParameters (const int&, char*[]); - static void showParameterUsage (); + static void showParameterUsage () + #if defined(__clang__) || defined(__GNUC__) + __attribute__((noreturn)) + #endif + ; static void closeConfirmationDialog (FWidget*, FCloseEvent*); // Callback method diff --git a/include/final/fmenu.h b/include/final/fmenu.h index 33dcfc3a..9b53a943 100644 --- a/include/final/fmenu.h +++ b/include/final/fmenu.h @@ -122,6 +122,21 @@ class FMenu : public FWindow, public FMenuList void cb_menuitem_toggled (FWidget*, data_ptr); private: + // Typedef + typedef struct + { + uChar focus_changed : 1; + uChar hide_sub_menu : 1; + uChar mouse_over_menu : 1; + uChar mouse_over_submenu : 1; + uChar mouse_over_supermenu : 1; + uChar mouse_over_menubar : 1; + uChar : 2; // padding bits + } mouseStates; + + // Constants + static const bool SELECT_ITEM = true; + // Disable copy constructor FMenu (const FMenu&); @@ -140,15 +155,28 @@ class FMenu : public FWindow, public FMenuList bool isMenu (FWidget*) const; bool isRadioMenuItem (FWidget*) const; bool isSubMenu() const; + bool isMouseOverMenu (const FPoint&); + bool isMouseOverSubmenu (const FPoint&); + bool isMouseOverSuperMenu (const FPoint&); + bool isMouseOverMenuBar (const FPoint&); // Methods void init(FWidget*); void calculateDimensions(); void adjustItems(); int adjustX(int); - void openSubMenu (FMenu*); + void openSubMenu (FMenu*, bool = false); + void closeOpenedSubMenu(); void hideSubMenus(); void hideSuperMenus(); + bool mouseDownOverList (FPoint); + bool mouseUpOverList (FPoint); + bool mouseMoveOverList (FPoint, mouseStates&); + void mouseUpOverBorder(); + void mouseMoveOverBorder (mouseStates&); + void passEventToSubMenu (FMouseEvent*& ev); + void passEventToSuperMenu (FMouseEvent*& ev); + void passEventToMenuBar (FMouseEvent*& ev); bool containsMenuStructure (const FPoint&); bool containsMenuStructure (int, int); FMenu* superMenuAt (const FPoint&); @@ -174,7 +202,8 @@ class FMenu : public FWindow, public FMenuList // Data Members FMenuItem* item; FWidget* super_menu; - FMenu* open_sub_menu; + FMenu* opened_sub_menu; + FMenu* shown_sub_menu; uInt max_item_width; bool mouse_down; bool has_checkable_items; diff --git a/include/final/fterm.h b/include/final/fterm.h index 916441c6..f8a14c39 100644 --- a/include/final/fterm.h +++ b/include/final/fterm.h @@ -329,8 +329,11 @@ class FTerm static FPoint& getMousePos(); static void setMousePos (const FPoint&); static void setMousePos (short, short); - static void exitWithMessage (std::string); - + static void exitWithMessage (std::string) + #if defined(__clang__) || defined(__GNUC__) + __attribute__((noreturn)) + #endif + ; // Data Members static int stdin_no; static int stdout_no; @@ -352,17 +355,15 @@ class FTerm static struct initializationValues { public: - initializationValues() - : terminal_detection(true) - , cursor_optimisation(true) - , color_change(true) - , vgafont(false) - , newfont(false) - , encoding(fc::UNKNOWN) - { } - - ~initializationValues() - { } + void setDefault() + { + terminal_detection = true; + cursor_optimisation = true; + color_change = true; + vgafont = false; + newfont = false; + encoding = fc::UNKNOWN; + } uInt8 terminal_detection : 1; uInt8 cursor_optimisation : 1; diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 95bf75e1..a0bcf836 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -318,6 +318,7 @@ FWidget* FApplication::processParameters (const int& argc, char* argv[]) showParameterUsage(); } + init_values.setDefault(); cmd_options (argc, argv); return 0; } @@ -753,7 +754,7 @@ inline void FApplication::sendKeyboardAccelerator() //---------------------------------------------------------------------- void FApplication::processKeyboardEvent() { - bool isKeyPressed = false; + bool isKeyPressed; FWidget* widget = findKeyboardWidget(); keyboardBufferTimeout(widget); flush_out(); diff --git a/src/flistbox.cpp b/src/flistbox.cpp index 38430071..e4e3de26 100644 --- a/src/flistbox.cpp +++ b/src/flistbox.cpp @@ -1251,12 +1251,13 @@ void FListBox::drawList() } //---------------------------------------------------------------------- -inline void FListBox::drawListLine ( int y, listBoxItems::iterator iter - , bool serach_mark ) +inline void FListBox::drawListLine ( int y + , listBoxItems::iterator iter + , bool serach_mark ) { uInt i, len; uInt inc_len = inc_search.getLength(); - bool isCurrentLine = bool(y + uInt(yoffset) + 1 == uInt(current)); + bool isCurrentLine = bool(y + yoffset + 1 == current); FString element; element = getString(iter).mid ( uInt(1 + xoffset) , uInt(getWidth() - nf_offset - 4) ); @@ -1292,8 +1293,9 @@ inline void FListBox::drawListLine ( int y, listBoxItems::iterator iter } //---------------------------------------------------------------------- -inline void FListBox::drawListBracketsLine ( int y, listBoxItems::iterator iter - , bool serach_mark ) +inline void FListBox::drawListBracketsLine ( int y + , listBoxItems::iterator iter + , bool serach_mark ) { int full_length; FString element; @@ -1301,7 +1303,7 @@ inline void FListBox::drawListBracketsLine ( int y, listBoxItems::iterator iter , inc_len = inc_search.getLength() , i = 0 , b = 0; - bool isCurrentLine = bool(y + uInt(yoffset) + 1 == uInt(current)); + bool isCurrentLine = bool(y + yoffset + 1 == current); if ( isMonochron() && isCurrentLine ) print ('>'); @@ -1408,7 +1410,7 @@ inline void FListBox::setLineAttributes ( int y , bool& serach_mark ) { bool isFocus = ((flags & fc::focus) != 0) - , isCurrentLine = bool(y + uInt(yoffset) + 1 == uInt(current)); + , isCurrentLine = bool(y + yoffset + 1 == current); uInt inc_len = inc_search.getLength(); setPrintPos (2, 2 + int(y)); diff --git a/src/fmenu.cpp b/src/fmenu.cpp index 4bf08008..198d8c9b 100644 --- a/src/fmenu.cpp +++ b/src/fmenu.cpp @@ -37,7 +37,8 @@ FMenu::FMenu(FWidget* parent) : FWindow(parent) , item(0) , super_menu(0) - , open_sub_menu(0) + , opened_sub_menu(0) + , shown_sub_menu(0) , max_item_width(0) , mouse_down(false) , has_checkable_items(false) @@ -50,7 +51,8 @@ FMenu::FMenu (const FString& txt, FWidget* parent) : FWindow(parent) , item(0) , super_menu(0) - , open_sub_menu(0) + , opened_sub_menu(0) + , shown_sub_menu(0) , max_item_width(0) , mouse_down(false) , has_checkable_items(false) @@ -150,7 +152,7 @@ void FMenu::onKeyPress (FKeyEvent* ev) if ( menubar ) { - FMenuBar* mbar = reinterpret_cast(menubar); + FMenuBar* mbar = static_cast(menubar); if ( mbar->hotkeyMenu(ev) ) return; @@ -165,7 +167,7 @@ void FMenu::onKeyPress (FKeyEvent* ev) FMenuItem* sel_item = getSelectedItem(); if ( sel_item->hasMenu() ) - openSubMenu (sel_item->getMenu()); + openSubMenu (sel_item->getMenu(), SELECT_ITEM); else { unselectItem(); @@ -187,7 +189,7 @@ void FMenu::onKeyPress (FKeyEvent* ev) case fc::Fkey_left: if ( isSubMenu() ) { - FMenu* smenu = reinterpret_cast(getSuperMenu()); + FMenu* smenu = static_cast(getSuperMenu()); hideSubMenus(); hide(); @@ -212,7 +214,7 @@ void FMenu::onKeyPress (FKeyEvent* ev) FMenu* sub_menu = getSelectedItem()->getMenu(); if ( ! sub_menu->isVisible() ) - openSubMenu (sub_menu); + openSubMenu (sub_menu, SELECT_ITEM); else keypressMenuBar(ev); // select next menu } @@ -228,7 +230,7 @@ void FMenu::onKeyPress (FKeyEvent* ev) if ( isSubMenu() ) { - FMenu* smenu = reinterpret_cast(getSuperMenu()); + FMenu* smenu = static_cast(getSuperMenu()); if ( smenu->getSelectedItem() ) smenu->getSelectedItem()->setFocus(); @@ -278,14 +280,15 @@ void FMenu::onKeyPress (FKeyEvent* ev) //---------------------------------------------------------------------- void FMenu::onMouseDown (FMouseEvent* ev) { + std::vector::const_iterator iter, last; + FPoint mouse_pos; + shown_sub_menu = 0; + if ( ev->getButton() != fc::LeftButton ) { - if ( open_sub_menu ) + if ( opened_sub_menu ) { - // close open sub menu - open_sub_menu->hideSubMenus(); - open_sub_menu->hide(); - open_sub_menu = 0; + closeOpenedSubMenu(); // close opened sub menu if ( getSelectedItem() ) getSelectedItem()->setFocus(); @@ -310,101 +313,15 @@ void FMenu::onMouseDown (FMouseEvent* ev) mouse_down = true; - if ( ! item_list.empty() ) - { - std::vector::const_iterator iter, last; - FMenu* show_sub_menu = 0; - bool focus_changed = false; - FPoint mouse_pos; + if ( item_list.empty() ) + return; - iter = item_list.begin(); - last = item_list.end(); - mouse_pos = ev->getPos(); - mouse_pos -= FPoint(getRightPadding(), getTopPadding()); + // Mouse pointer over menu list changed focus + if ( mouseDownOverList (ev->getPos()) ) + redraw(); - while ( iter != last ) - { - int x1 = (*iter)->getX() - , x2 = (*iter)->getX() + (*iter)->getWidth() - , y = (*iter)->getY() - , mouse_x = mouse_pos.getX() - , mouse_y = mouse_pos.getY(); - - if ( mouse_x >= x1 - && mouse_x < x2 - && mouse_y == y ) - { - // 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 ( getStatusBar() ) - getStatusBar()->drawMessage(); - - updateTerminal(); - flush_out(); - } - } - } - - if ( ! (*iter)->isSelected() ) - { - unselectItem(); - FWidget* focused_widget = getFocusWidget(); - FFocusEvent out (fc::FocusOut_Event); - FApplication::queueEvent(focused_widget, &out); - (*iter)->setSelected(); - setSelectedItem(*iter); - (*iter)->setFocus(); - - if ( focused_widget ) - focused_widget->redraw(); - - if ( getStatusBar() ) - getStatusBar()->drawMessage(); - - if ( (*iter)->hasMenu() ) - { - FMenu* sub_menu = (*iter)->getMenu(); - if ( ! sub_menu->isVisible() ) - show_sub_menu = sub_menu; - } - - focus_changed = true; - } - } - - ++iter; - } - - if ( focus_changed ) - 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(); - } - } + // Open the sub menu to be opened + openSubMenu(shown_sub_menu); } //---------------------------------------------------------------------- @@ -417,308 +334,79 @@ void FMenu::onMouseUp (FMouseEvent* ev) { mouse_down = false; - if ( ! item_list.empty() ) - { - std::vector::const_iterator iter, last; - FPoint mouse_pos; - iter = item_list.begin(); - last = item_list.end(); - mouse_pos = ev->getPos(); - mouse_pos -= FPoint(getRightPadding(), getTopPadding()); + if ( item_list.empty() ) + return; - while ( iter != last ) - { - int x1 = (*iter)->getX() - , x2 = (*iter)->getX() + (*iter)->getWidth() - , y = (*iter)->getY(); + // Mouse pointer over an entry in the menu list + if ( mouseUpOverList (ev->getPos()) ) + return; - if ( (*iter)->isSelected() ) - { - int mouse_x = mouse_pos.getX(); - int mouse_y = mouse_pos.getY(); - - if ( mouse_x >= x1 - && mouse_x < x2 - && mouse_y == y ) - { - // Mouse pointer over item - if ( (*iter)->hasMenu() ) - { - FMenu* sub_menu = (*iter)->getMenu(); - if ( ! sub_menu->isVisible() ) - openSubMenu (sub_menu); - else if ( open_sub_menu ) - { - open_sub_menu->selectFirstItem(); - - if ( open_sub_menu->hasSelectedItem() ) - open_sub_menu->getSelectedItem()->setFocus(); - - open_sub_menu->redraw(); - - if ( getStatusBar() ) - getStatusBar()->drawMessage(); - - updateTerminal(); - flush_out(); - } - - return; - } - else - { - unselectItem(); - hide(); - hideSuperMenus(); - (*iter)->processClicked(); - } - } - } - - ++iter; - } - - // Click on a non-FMenuItem (border or separator line) - unselectItem(); - hide(); - hideSuperMenus(); - } + // Click on a non-FMenuItem (border or separator line) + mouseUpOverBorder(); } } //---------------------------------------------------------------------- void FMenu::onMouseMove (FMouseEvent* ev) { + mouseStates state; + // Set all state flags to false + std::memset (&state, 0, sizeof(state)); + shown_sub_menu = 0; + if ( ev->getButton() != fc::LeftButton ) return; if ( ! isWindowActive() ) setActiveWindow(this); - if ( mouse_down && ! item_list.empty() ) + if ( ! mouse_down || item_list.empty() ) + return; + + state.mouse_over_menu = isMouseOverMenu (ev->getTermPos()); + state.mouse_over_submenu = isMouseOverSubmenu (ev->getTermPos()); + state.mouse_over_supermenu = isMouseOverSuperMenu (ev->getTermPos()); + state.mouse_over_menubar = isMouseOverMenuBar (ev->getTermPos()); + + // Mouse pointer over an entry in the menu list + mouseMoveOverList (ev->getPos(), state); + + if ( state.mouse_over_submenu ) { - std::vector::const_iterator iter, last; - FMenu* smenu = 0; - bool focus_changed = false - , mouse_over_menu = false - , mouse_over_submenu = false - , mouse_over_supermenu = false - , mouse_over_menubar = false - , hide_sub_menu = false; - FMenu* show_sub_menu = 0; - FPoint mouse_pos; + passEventToSubMenu(ev); // Event handover to sub-menu + return; + } - iter = item_list.begin(); - last = item_list.end(); - mouse_pos = ev->getPos(); - mouse_pos -= FPoint(getRightPadding(), getTopPadding()); + if ( ! state.mouse_over_menu && state.mouse_over_supermenu ) + { + passEventToSuperMenu(ev); // Event handover to super-menu + return; + } - if ( getTermGeometry().contains(ev->getTermPos()) ) - mouse_over_menu = true; + if ( state.mouse_over_menubar ) + { + passEventToMenuBar(ev); // Event handover to the menu bar + return; + } - if ( open_sub_menu ) - { - const FRect& submenu_geometry = open_sub_menu->getTermGeometry(); - if ( submenu_geometry.contains(ev->getTermPos()) ) - mouse_over_submenu = true; - } + if ( ! hasSelectedItem() && state.mouse_over_menu ) + { + mouseMoveOverBorder(state); // Mouse is over border or separator + } - if ( isSubMenu() ) - { - smenu = superMenuAt (ev->getTermPos()); + if ( state.focus_changed ) + redraw(); - if ( smenu ) - mouse_over_supermenu = true; - } - - if ( getMenuBar() - && isMenuBar(getMenuBar()) - && getMenuBar()->getTermGeometry().contains(ev->getTermPos()) ) - { - mouse_over_menubar = true; - } - - while ( iter != last ) - { - int x1 = (*iter)->getX() - , x2 = (*iter)->getX() + (*iter)->getWidth() - , y = (*iter)->getY() - , mouse_x = mouse_pos.getX() - , mouse_y = mouse_pos.getY(); - - if ( mouse_x >= x1 - && mouse_x < x2 - && mouse_y == y ) - { - if ( (*iter)->isEnabled() - && ! (*iter)->isSelected() - && ! (*iter)->isSeparator() ) - { - // Mouse pointer over item - FWidget* focused_widget = getFocusWidget(); - FFocusEvent out (fc::FocusOut_Event); - FApplication::queueEvent(focused_widget, &out); - (*iter)->setSelected(); - setSelectedItem(*iter); - (*iter)->setFocus(); - - if ( focused_widget ) - focused_widget->redraw(); - - if ( getStatusBar() ) - getStatusBar()->drawMessage(); - - // sub menu handling - if ( (*iter)->hasMenu() ) - { - FMenu* sub_menu = (*iter)->getMenu(); - - if ( ! sub_menu->isVisible() ) - show_sub_menu = sub_menu; - } - else if ( open_sub_menu ) - hide_sub_menu = true; - - focus_changed = true; - } - } - else - { - if ( mouse_over_menu - && (*iter)->isEnabled() - && (*iter)->isSelected() - && ! mouse_over_submenu ) - { - // Unselect selected item without mouse focus - (*iter)->unsetSelected(); - (*iter)->unsetFocus(); - - if ( getSelectedItem() == *iter ) - setSelectedItem(0); - - focus_changed = true; - } - } - - ++iter; - } - - if ( mouse_over_submenu ) - { - // Mouse event handover to sub-menu - const FPoint& t = ev->getTermPos(); - const FPoint& p = open_sub_menu->termToWidgetPos(t); - int b = ev->getButton(); - - try - { - FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b); - open_sub_menu->mouse_down = true; - setClickedWidget(open_sub_menu); - open_sub_menu->onMouseMove(_ev); - delete _ev; - } - catch (const std::bad_alloc& ex) - { - std::cerr << "not enough memory to alloc " << ex.what() << std::endl; - } - - return; - } - else if ( ! mouse_over_menu && mouse_over_supermenu ) - { - // Mouse event handover to super-menu - const FPoint& t = ev->getTermPos(); - const FPoint& p = smenu->termToWidgetPos(t); - int b = ev->getButton(); - - try - { - FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b); - smenu->mouse_down = true; - setClickedWidget(smenu); - smenu->onMouseMove(_ev); - delete _ev; - } - catch (const std::bad_alloc& ex) - { - std::cerr << "not enough memory to alloc " << ex.what() << std::endl; - } - - return; - } - else if ( mouse_over_menubar ) - { - // Mouse event handover to the menu bar - FWidget* menubar = getMenuBar(); - const FPoint& t = ev->getTermPos(); - const FPoint& p = menubar->termToWidgetPos(t); - int b = ev->getButton(); - - try - { - FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b); - setClickedWidget(menubar); - FMenuBar* mbar = reinterpret_cast(menubar); - mbar->mouse_down = true; - mbar->onMouseMove(_ev); - delete _ev; - } - catch (const std::bad_alloc& ex) - { - std::cerr << "not enough memory to alloc " << ex.what() << std::endl; - } - - return; - } - else if ( ! hasSelectedItem() && mouse_over_menu ) - { - // Mouse is over border or separator - if ( getStatusBar() ) - { - const FString& msg = getStatusbarMessage(); - const FString& curMsg = getStatusBar()->getMessage(); - - if ( curMsg != msg ) - { - getStatusBar()->setMessage(msg); - getStatusBar()->drawMessage(); - } - } - - if ( open_sub_menu ) - hide_sub_menu = true; - } - - if ( focus_changed ) - redraw(); - - if ( show_sub_menu ) - { - // close open sub menu - if ( open_sub_menu ) - { - open_sub_menu->hideSubMenus(); - open_sub_menu->hide(); - } - - // 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(); - } - else if ( hide_sub_menu ) - { - open_sub_menu->hideSubMenus(); - open_sub_menu->hide(); - open_sub_menu = 0; - updateTerminal(); - flush_out(); - } + if ( shown_sub_menu ) + { + closeOpenedSubMenu(); + openSubMenu (shown_sub_menu); + } + else if ( state.hide_sub_menu ) + { + closeOpenedSubMenu(); + updateTerminal(); + flush_out(); } } @@ -790,6 +478,53 @@ bool FMenu::isSubMenu() const return false; } +//---------------------------------------------------------------------- +bool FMenu::isMouseOverMenu (const FPoint& termpos) +{ + if ( getTermGeometry().contains(termpos) ) + return true; + + return false; +} + +//---------------------------------------------------------------------- +bool FMenu::isMouseOverSubmenu (const FPoint& termpos) +{ + if ( opened_sub_menu ) + { + const FRect& submenu_geometry = opened_sub_menu->getTermGeometry(); + + if ( submenu_geometry.contains(termpos) ) + return true; + } + + return false; +} + +//---------------------------------------------------------------------- +bool FMenu::isMouseOverSuperMenu (const FPoint& termpos) +{ + FMenu* smenu = superMenuAt (termpos); + + if ( smenu ) + return true; + + return false; +} + +//---------------------------------------------------------------------- +bool FMenu::isMouseOverMenuBar (const FPoint& termpos) +{ + if ( getMenuBar() + && isMenuBar(getMenuBar()) + && getMenuBar()->getTermGeometry().contains(termpos) ) + { + return true; + } + + return false; +} + //---------------------------------------------------------------------- void FMenu::init(FWidget* parent) { @@ -937,20 +672,27 @@ int FMenu::adjustX (int x_pos) } //---------------------------------------------------------------------- -void FMenu::openSubMenu (FMenu* sub_menu) +void FMenu::openSubMenu (FMenu* sub_menu, bool select) { + // open sub menu + + if ( ! sub_menu ) + return; + if ( sub_menu->isVisible() ) return; - // open sub menu - sub_menu->selectFirstItem(); + if ( select ) + { + sub_menu->selectFirstItem(); - if ( sub_menu->hasSelectedItem() ) - sub_menu->getSelectedItem()->setFocus(); + if ( sub_menu->hasSelectedItem() ) + sub_menu->getSelectedItem()->setFocus(); + } sub_menu->setVisible(); sub_menu->show(); - open_sub_menu = sub_menu; + opened_sub_menu = sub_menu; raiseWindow (sub_menu); sub_menu->redraw(); @@ -961,15 +703,27 @@ void FMenu::openSubMenu (FMenu* sub_menu) flush_out(); } +//---------------------------------------------------------------------- +void FMenu::closeOpenedSubMenu() +{ + // close sub menu + if ( ! opened_sub_menu ) + return; + + opened_sub_menu->hideSubMenus(); + opened_sub_menu->hide(); + opened_sub_menu = 0; +} + //---------------------------------------------------------------------- void FMenu::hideSubMenus() { // hide all sub-menus - if ( open_sub_menu ) + if ( opened_sub_menu ) { - open_sub_menu->hideSubMenus(); - open_sub_menu->hide(); - open_sub_menu = 0; + opened_sub_menu->hideSubMenus(); + opened_sub_menu->hide(); + opened_sub_menu = 0; } unselectItem(); @@ -985,34 +739,360 @@ void FMenu::hideSuperMenus() { if ( isMenuBar(super) ) { - FMenuBar* mbar = reinterpret_cast(super); + FMenuBar* mbar = static_cast(super); if ( mbar->hasSelectedItem() ) mbar->leaveMenuBar(); } else if ( isMenu(super) ) { - FMenu* m = reinterpret_cast(super); + FMenu* m = static_cast(super); m->hide(); m->hideSuperMenus(); } else if ( isWindowsMenu(super) ) { - FDialog* dgl = reinterpret_cast(super); + FDialog* dgl = static_cast(super); dgl->leaveMenu(); } } } +//---------------------------------------------------------------------- +bool FMenu::mouseDownOverList (FPoint mouse_pos) +{ + std::vector::const_iterator iter, last; + bool focus_changed = false; + iter = item_list.begin(); + last = item_list.end(); + mouse_pos -= FPoint(getRightPadding(), getTopPadding()); + + while ( iter != last ) + { + int x1 = (*iter)->getX() + , x2 = (*iter)->getX() + (*iter)->getWidth() + , y = (*iter)->getY() + , mouse_x = mouse_pos.getX() + , mouse_y = mouse_pos.getY(); + + if ( mouse_x >= x1 + && mouse_x < x2 + && mouse_y == y ) + { + // Mouse pointer over item + if ( hasSelectedItem() ) + { + FMenuItem* sel_item = getSelectedItem(); + + if ( sel_item + && sel_item->hasMenu() + && sel_item->getMenu() == opened_sub_menu ) + { + if ( sel_item != *iter ) + hideSubMenus(); + else + { + // unselect sub menu items + opened_sub_menu->unselectItem(); + raiseWindow (opened_sub_menu); + opened_sub_menu->redraw(); + sel_item->setFocus(); + + if ( getStatusBar() ) + getStatusBar()->drawMessage(); + + updateTerminal(); + flush_out(); + } + } + } + + if ( ! (*iter)->isSelected() ) + { + unselectItem(); + FWidget* focused_widget = getFocusWidget(); + FFocusEvent out (fc::FocusOut_Event); + FApplication::queueEvent(focused_widget, &out); + (*iter)->setSelected(); + setSelectedItem(*iter); + (*iter)->setFocus(); + + if ( focused_widget ) + focused_widget->redraw(); + + if ( getStatusBar() ) + getStatusBar()->drawMessage(); + + if ( (*iter)->hasMenu() ) + { + FMenu* sub_menu = (*iter)->getMenu(); + if ( ! sub_menu->isVisible() ) + shown_sub_menu = sub_menu; + } + + focus_changed = true; + } + } + + ++iter; + } + + return focus_changed; +} + +//---------------------------------------------------------------------- +bool FMenu::mouseUpOverList (FPoint mouse_pos) +{ + std::vector::const_iterator iter, last; + iter = item_list.begin(); + last = item_list.end(); + mouse_pos -= FPoint(getRightPadding(), getTopPadding()); + + while ( iter != last ) + { + int x1 = (*iter)->getX() + , x2 = (*iter)->getX() + (*iter)->getWidth() + , y = (*iter)->getY() + , mouse_x = mouse_pos.getX() + , mouse_y = mouse_pos.getY(); + + if ( (*iter)->isSelected() + && mouse_x >= x1 + && mouse_x < x2 + && mouse_y == y ) + { + // Mouse pointer over item + if ( (*iter)->hasMenu() ) + { + FMenu* sub_menu = (*iter)->getMenu(); + if ( ! sub_menu->isVisible() ) + openSubMenu (sub_menu, SELECT_ITEM); + else if ( opened_sub_menu ) + { + opened_sub_menu->selectFirstItem(); + + if ( opened_sub_menu->hasSelectedItem() ) + opened_sub_menu->getSelectedItem()->setFocus(); + + opened_sub_menu->redraw(); + + if ( getStatusBar() ) + getStatusBar()->drawMessage(); + + updateTerminal(); + flush_out(); + } + + return true; + } + else + { + unselectItem(); + hide(); + hideSuperMenus(); + (*iter)->processClicked(); + } + } + + ++iter; + } + + return false; +} + +//---------------------------------------------------------------------- +bool FMenu::mouseMoveOverList (FPoint mouse_pos, mouseStates& state) +{ + std::vector::const_iterator iter, last; + bool isOverList = false; + iter = item_list.begin(); + last = item_list.end(); + mouse_pos -= FPoint(getRightPadding(), getTopPadding()); + + while ( iter != last ) + { + int x1 = (*iter)->getX() + , x2 = (*iter)->getX() + (*iter)->getWidth() + , y = (*iter)->getY() + , mouse_x = mouse_pos.getX() + , mouse_y = mouse_pos.getY(); + + if ( mouse_x >= x1 + && mouse_x < x2 + && mouse_y == y ) + { + if ( (*iter)->isEnabled() + && ! (*iter)->isSelected() + && ! (*iter)->isSeparator() ) + { + // Mouse pointer over item + FWidget* focused_widget = getFocusWidget(); + FFocusEvent out (fc::FocusOut_Event); + FApplication::queueEvent(focused_widget, &out); + (*iter)->setSelected(); + setSelectedItem(*iter); + (*iter)->setFocus(); + + if ( focused_widget ) + focused_widget->redraw(); + + if ( getStatusBar() ) + getStatusBar()->drawMessage(); + + // Sub menu handling + if ( (*iter)->hasMenu() ) + { + FMenu* sub_menu = (*iter)->getMenu(); + + if ( ! sub_menu->isVisible() ) + shown_sub_menu = sub_menu; + } + else if ( opened_sub_menu ) + state.hide_sub_menu = true; + + state.focus_changed = true; + } + + if ( ! (*iter)->isSeparator() ) + isOverList = true; + } + else + { + if ( state.mouse_over_menu + && (*iter)->isEnabled() + && (*iter)->isSelected() + && ! state.mouse_over_submenu ) + { + // Unselect selected item without mouse focus + (*iter)->unsetSelected(); + (*iter)->unsetFocus(); + + if ( getSelectedItem() == *iter ) + setSelectedItem(0); + + state.focus_changed = true; + } + } + + ++iter; + } + + return isOverList; +} + +//---------------------------------------------------------------------- +void FMenu::mouseUpOverBorder() +{ + // Mouse button up over border or separator line + + unselectItem(); + hide(); + hideSuperMenus(); +} + +//---------------------------------------------------------------------- +void FMenu::mouseMoveOverBorder (mouseStates& state) +{ + // Mouse is moved over border or separator line + + if ( getStatusBar() ) + { + const FString& msg = getStatusbarMessage(); + const FString& curMsg = getStatusBar()->getMessage(); + + if ( curMsg != msg ) + { + getStatusBar()->setMessage(msg); + getStatusBar()->drawMessage(); + } + } + + if ( opened_sub_menu ) + state.hide_sub_menu = true; +} + +//---------------------------------------------------------------------- +void FMenu::passEventToSubMenu (FMouseEvent*& ev) +{ + // Mouse event handover to sub-menu + + const FPoint& t = ev->getTermPos(); + const FPoint& p = opened_sub_menu->termToWidgetPos(t); + int b = ev->getButton(); + + try + { + FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b); + opened_sub_menu->mouse_down = true; + setClickedWidget(opened_sub_menu); + opened_sub_menu->onMouseMove(_ev); + delete _ev; + } + catch (const std::bad_alloc& ex) + { + std::cerr << "not enough memory to alloc " << ex.what() << std::endl; + } +} + +//---------------------------------------------------------------------- +void FMenu::passEventToSuperMenu (FMouseEvent*& ev) +{ + // Mouse event handover to super-menu + + FMenu* smenu = superMenuAt (ev->getTermPos()); + const FPoint& t = ev->getTermPos(); + const FPoint& p = smenu->termToWidgetPos(t); + int b = ev->getButton(); + + try + { + FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b); + smenu->mouse_down = true; + setClickedWidget(smenu); + smenu->onMouseMove(_ev); + delete _ev; + } + catch (const std::bad_alloc& ex) + { + std::cerr << "not enough memory to alloc " << ex.what() << std::endl; + } +} + +//---------------------------------------------------------------------- +void FMenu::passEventToMenuBar (FMouseEvent*& ev) +{ + // Mouse event handover to the menu bar + + FWidget* menubar = getMenuBar(); + const FPoint& t = ev->getTermPos(); + const FPoint& p = menubar->termToWidgetPos(t); + int b = ev->getButton(); + + try + { + FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, t, b); + setClickedWidget(menubar); + FMenuBar* mbar = static_cast(menubar); + mbar->mouse_down = true; + mbar->onMouseMove(_ev); + delete _ev; + } + catch (const std::bad_alloc& ex) + { + std::cerr << "not enough memory to alloc " << ex.what() << std::endl; + } +} + //---------------------------------------------------------------------- bool FMenu::containsMenuStructure (int x, int y) { // Check mouse click position for item, menu and all sub menus + FMenuItem* si = getSelectedItem(); if ( getTermGeometry().contains(x, y) ) return true; - else if ( si && si->hasMenu() && open_sub_menu ) + else if ( si && si->hasMenu() && opened_sub_menu ) return si->getMenu()->containsMenuStructure(x, y); else if ( item && item->getTermGeometry().contains(x, y) ) return true; @@ -1024,6 +1104,7 @@ bool FMenu::containsMenuStructure (int x, int y) FMenu* FMenu::superMenuAt (int x, int y) { // Check mouse click position for super menu + if ( getTermGeometry().contains(x, y) ) return 0; @@ -1187,7 +1268,7 @@ bool FMenu::hotkeyMenu (FKeyEvent*& ev) (*iter)->setSelected(); setSelectedItem (*iter); redraw(); - openSubMenu (sub_menu); + openSubMenu (sub_menu, SELECT_ITEM); sub_menu->redraw(); } else diff --git a/src/fterm.cpp b/src/fterm.cpp index 0cb6fd57..8d6fc62a 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -1480,7 +1480,8 @@ void FTerm::setEncoding (fc::encoding enc) break; case fc::ASCII: - default: + case fc::UNKNOWN: + case fc::NUM_OF_ENCODINGS: Fputchar = &FTerm::putchar_ASCII; } @@ -1913,7 +1914,7 @@ void FTerm::exitWithMessage (std::string message) if ( exit_message[0] ) std::fprintf (stderr, "Warning: %s\n", exit_message); - exit (EXIT_FAILURE); + std::exit (EXIT_FAILURE); } diff --git a/src/fvterm.cpp b/src/fvterm.cpp index ff8c3052..0216b50e 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -2373,7 +2373,6 @@ bool FVTerm::canClearLeadingWS (uInt& xmin, uInt y) // => clear from xmin to beginning of line term_area*& vt = vterm; - bool& ut = FTermcap::background_color_erase; char*& cb = TCAP(fc::t_clr_bol); char_data* first_char = &vt->text[y * uInt(vt->width)]; @@ -2381,6 +2380,7 @@ bool FVTerm::canClearLeadingWS (uInt& xmin, uInt y) { uInt leading_whitespace = 1; bool normal = isNormal(first_char); + bool& ut = FTermcap::background_color_erase; for (uInt x = 1; x < uInt(vt->width); x++) {