Hello community, here is the log from the commit of package libyui-ncurses for openSUSE:Factory checked in at 2020-08-20 22:24:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libyui-ncurses (Old) and /work/SRC/openSUSE:Factory/.libyui-ncurses.new.3399 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libyui-ncurses" Thu Aug 20 22:24:51 2020 rev:57 rq:827300 version:2.56.1 Changes: -------- --- /work/SRC/openSUSE:Factory/libyui-ncurses/libyui-ncurses.changes 2020-08-14 13:08:32.653192253 +0200 +++ /work/SRC/openSUSE:Factory/.libyui-ncurses.new.3399/libyui-ncurses.changes 2020-08-20 22:26:18.439910562 +0200 @@ -1,0 +2,7 @@ +Wed Aug 12 15:46:18 UTC 2020 - José Iván López González <[email protected]> + +- Handle hot-keys for top level menu options. +- Related to bsc#1175115. +- 2.56.1 + +------------------------------------------------------------------- Old: ---- libyui-ncurses-2.56.0.tar.bz2 New: ---- libyui-ncurses-2.56.1.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libyui-ncurses-doc.spec ++++++ --- /var/tmp/diff_new_pack.IP0O74/_old 2020-08-20 22:26:19.967911277 +0200 +++ /var/tmp/diff_new_pack.IP0O74/_new 2020-08-20 22:26:19.971911279 +0200 @@ -20,7 +20,7 @@ %define so_version 13 Name: %{parent}-doc -Version: 2.56.0 +Version: 2.56.1 Release: 0 Source: %{parent}-%{version}.tar.bz2 ++++++ libyui-ncurses.spec ++++++ --- /var/tmp/diff_new_pack.IP0O74/_old 2020-08-20 22:26:19.999911292 +0200 +++ /var/tmp/diff_new_pack.IP0O74/_new 2020-08-20 22:26:20.003911294 +0200 @@ -17,7 +17,7 @@ Name: libyui-ncurses -Version: 2.56.0 +Version: 2.56.1 Release: 0 Source: %{name}-%{version}.tar.bz2 ++++++ libyui-ncurses-2.56.0.tar.bz2 -> libyui-ncurses-2.56.1.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/SOURCECONF.cmake new/libyui-ncurses-2.56.1/SOURCECONF.cmake --- old/libyui-ncurses-2.56.0/SOURCECONF.cmake 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/SOURCECONF.cmake 2020-08-17 12:29:15.000000000 +0200 @@ -79,6 +79,7 @@ NCi18n.h tnode.h position.h + CyclicContainer.h YNCursesUI.h NCtoY2Event.h NCApplication.h diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/VERSION.cmake new/libyui-ncurses-2.56.1/VERSION.cmake --- old/libyui-ncurses-2.56.0/VERSION.cmake 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/VERSION.cmake 2020-08-17 12:29:15.000000000 +0200 @@ -1,6 +1,6 @@ SET( VERSION_MAJOR "2" ) SET( VERSION_MINOR "56" ) -SET( VERSION_PATCH "0" ) +SET( VERSION_PATCH "1" ) SET( VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${GIT_SHA1_VERSION}" ) ##### This is needed for the libyui core ONLY. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/package/libyui-ncurses-doc.spec new/libyui-ncurses-2.56.1/package/libyui-ncurses-doc.spec --- old/libyui-ncurses-2.56.0/package/libyui-ncurses-doc.spec 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/package/libyui-ncurses-doc.spec 2020-08-17 12:29:15.000000000 +0200 @@ -19,7 +19,7 @@ %define so_version 13 Name: %{parent}-doc -Version: 2.56.0 +Version: 2.56.1 Release: 0 Source: %{parent}-%{version}.tar.bz2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/package/libyui-ncurses.changes new/libyui-ncurses-2.56.1/package/libyui-ncurses.changes --- old/libyui-ncurses-2.56.0/package/libyui-ncurses.changes 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/package/libyui-ncurses.changes 2020-08-17 12:29:15.000000000 +0200 @@ -1,4 +1,11 @@ ------------------------------------------------------------------- +Wed Aug 12 15:46:18 UTC 2020 - José Iván López González <[email protected]> + +- Handle hot-keys for top level menu options. +- Related to bsc#1175115. +- 2.56.1 + +------------------------------------------------------------------- Tue Aug 11 22:15:17 UTC 2020 - José Iván López González <[email protected]> - Add MenuBar widget (bsc#1175115). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/package/libyui-ncurses.spec new/libyui-ncurses-2.56.1/package/libyui-ncurses.spec --- old/libyui-ncurses-2.56.0/package/libyui-ncurses.spec 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/package/libyui-ncurses.spec 2020-08-17 12:29:15.000000000 +0200 @@ -17,7 +17,7 @@ Name: libyui-ncurses -Version: 2.56.0 +Version: 2.56.1 Release: 0 Source: %{name}-%{version}.tar.bz2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/src/CyclicContainer.h new/libyui-ncurses-2.56.1/src/CyclicContainer.h --- old/libyui-ncurses-2.56.0/src/CyclicContainer.h 1970-01-01 01:00:00.000000000 +0100 +++ new/libyui-ncurses-2.56.1/src/CyclicContainer.h 2020-08-17 12:29:15.000000000 +0200 @@ -0,0 +1,146 @@ +/* + Copyright (C) 2020 SUSE LLC + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: CyclicContainer.h + + Author: Jose Iván López <[email protected]> + +/-*/ + + +#ifndef CyclicContainer_h +#define CyclicContainer_h + +#include <algorithm> +#include <iterator> +#include <vector> + +/** Container class that allows cyclic navigation between its elements by moving to the next/previous + * element. + * + * @note This class holds pointers, but it does not own the pointers. + **/ +template <class T> +class CyclicContainer +{ +public: + + using Iterator = typename std::vector<T *>::iterator; + using ReverseIterator = std::reverse_iterator<Iterator>; + + Iterator begin() { return _elements.begin(); } + Iterator end() { return _elements.end(); } + + CyclicContainer() : _elements(), _current( nullptr ) + {} + + + ~CyclicContainer() + { + clear(); + } + + + void clear() + { + _elements.clear(); + _current = nullptr; + } + + + void add( T * element ) + { + _elements.push_back(element); + } + + + void setCurrent(Iterator element) + { + if ( element != _elements.end() ) + _current = *element; + } + + + Iterator current() + { + return std::find( _elements.begin(), _elements.end(), _current ); + } + + + Iterator next() + { + Iterator current = this->current(); + + if ( current == _elements.end() ) + return findNext( _elements.begin() ); + + Iterator next = findNext( std::next( current, 1 ) ); + + if ( next == _elements.end() ) + return findNext( _elements.begin() ); + + return next; + } + + + Iterator previous() + { + Iterator current = this->current(); + + ReverseIterator rbegin; + + if ( current == _elements.end() ) + rbegin = _elements.rbegin(); + else + rbegin = ReverseIterator( current ); + + ReverseIterator previous = findPrevious( rbegin ); + + if ( previous == _elements.rend() && rbegin != _elements.rbegin() ) + previous = findPrevious( _elements.rbegin() ); + + if ( previous == _elements.rend() ) + return _elements.end(); + + return find( _elements.begin(), _elements.end(), *previous ); + } + +private: + + Iterator findNext( Iterator begin ) + { + return find_if( begin, _elements.end(), [](const T * element) { + return element->isSelectable(); + }); + } + + + ReverseIterator findPrevious( ReverseIterator rbegin ) + { + return find_if( rbegin, _elements.rend(), [](const T * element) { + return element->isSelectable(); + }); + } + + + std::vector<T *> _elements; + + T * _current; +}; + +#endif // CyclicContainer_h diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/src/NCMenuBar.cc new/libyui-ncurses-2.56.1/src/NCMenuBar.cc --- old/libyui-ncurses-2.56.0/src/NCMenuBar.cc 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/src/NCMenuBar.cc 2020-08-17 12:29:15.000000000 +0200 @@ -18,13 +18,12 @@ File: NCMenuBar.cc - Author: Stefan Hundhammer <[email protected]> + Author: Jose Iván López <[email protected]> /-*/ -#include <algorithm> // std::max() -#include <iterator> +#include <algorithm> #define YUILogComponent "ncurses" #include <yui/YUILog.h> @@ -40,14 +39,40 @@ #define SPACING 2 -struct NCMenuBar::Menu { +// Helper class that represents a top level menu +struct NCMenuBar::Menu +{ wpos position; YMenuItem* item; + + + // Whether the menu can be selected + bool isSelectable() const + { + if ( ! item ) + return false; + + return item->isEnabled(); + } + + + // Whether the menu contains the given hot-key + bool hasHotkey( int key ) const + { + NClabel label = NCstring( item->label() ); + label.stripHotkey(); + + if ( ! label.hasHotkey() ) + return false; + + return tolower( key ) == tolower( label.hotkey() ); + } + }; NCMenuBar::NCMenuBar( YWidget* parent ) : - YMenuBar( parent ), NCWidget( parent ), _selectedMenu( nullptr ) + YMenuBar( parent ), NCWidget( parent ), _menus() { defsze = wsze( 1, 10 ); } @@ -67,7 +92,6 @@ _menus.clear(); - _selectedMenu = nullptr; defsze = wsze( 1, 10 ); } @@ -91,7 +115,7 @@ menu->item = item; menu->position = wpos( 0, width ); - _menus.push_back( menu ); + _menus.add( menu ); item->setUiItem( menu ); NClabel label( NCstring( menu->item->label() ) ); @@ -100,7 +124,7 @@ width += label.width() + SPACING; } - selectMenu( findNextEnabledMenu( _menus.begin() ) ); + selectNextMenu(); defsze = wsze( 1, width ); } @@ -137,22 +161,22 @@ NCursesEvent NCMenuBar::postMenu() { - wpos at(ScreenPos() + wpos( 1, _selectedMenu->position.C) ); + wpos at(ScreenPos() + wpos( 1, selectedMenu()->position.C) ); NCPopupMenu * dialog = new NCPopupMenu( at, - _selectedMenu->item->childrenBegin(), - _selectedMenu->item->childrenEnd() + selectedMenu()->item->childrenBegin(), + selectedMenu()->item->childrenEnd() ); YUI_CHECK_NEW( dialog ); NCursesEvent event; - int selectedIndex = dialog->post( &event ); + dialog->post( &event ); YDialog::deleteTopmostDialog(); - return handlePostMenu( event, selectedIndex ); + return handlePostMenu( event ); } @@ -188,12 +212,12 @@ switch ( key ) { case KEY_LEFT: - selectMenu( previousMenu() ); + selectPreviousMenu(); wRedraw(); break; case KEY_RIGHT: - selectMenu( nextMenu() ); + selectNextMenu(); wRedraw(); break; @@ -252,134 +276,92 @@ bool NCMenuBar::HasHotkey( int key ) { - // TODO - return false; + if( key < 0 || UCHAR_MAX < key ) + return false; + + return findMenuWithHotkey( key ) != _menus.end(); } NCursesEvent NCMenuBar::wHandleHotkey( wint_t key ) { - // TODO - NCursesEvent event = NCursesEvent::none; + CyclicContainer<Menu>::Iterator menu = findMenuWithHotkey( key ); - return event; + if ( menu == _menus.end() ) + return NCursesEvent::none; + + _menus.setCurrent( menu ); + + wRedraw(); + return postMenu(); } NCursesEvent -NCMenuBar::handlePostMenu( const NCursesEvent & event, int selectedIndex ) +NCMenuBar::handlePostMenu( const NCursesEvent & event ) { - NCursesEvent new_event = NCursesEvent::none; + NCursesEvent newEvent = NCursesEvent::none; - if ( event == NCursesEvent::button && selectedIndex >= 0 ) + if ( event == NCursesEvent::button ) { - YMenuItem * item = findMenuItem( selectedIndex ); - - if ( item && item->isEnabled() ) - { - new_event = NCursesEvent::menu; - new_event.selection = item; - } + newEvent = NCursesEvent::menu; + newEvent.selection = event.selection; } else if ( event == NCursesEvent::key ) { if ( event.keySymbol == "CursorLeft" ) { wHandleInput( KEY_LEFT ); - new_event = wHandleInput( KEY_DOWN ); + newEvent = wHandleInput( KEY_DOWN ); } else if ( event.keySymbol == "CursorRight" ) { wHandleInput( KEY_RIGHT ); - new_event = wHandleInput( KEY_DOWN ); + newEvent = wHandleInput( KEY_DOWN ); } } - return new_event; + return newEvent; } -void -NCMenuBar::selectMenu( NCMenuBar::MenuIterator menu ) -{ - if ( menu != _menus.end() ) - _selectedMenu = *menu; -} - - -NCMenuBar::MenuIterator -NCMenuBar::currentMenu() +NCMenuBar::Menu * +NCMenuBar::selectedMenu() { - return std::find( _menus.begin(), _menus.end(), _selectedMenu ); -} - - -NCMenuBar::MenuIterator -NCMenuBar::nextMenu() -{ - MenuIterator current = currentMenu(); - - if ( current == _menus.end() ) - return findNextEnabledMenu( _menus.begin() ); - - MenuIterator next = findNextEnabledMenu( std::next( current, 1 ) ); - - if ( next == _menus.end() ) - return findNextEnabledMenu( _menus.begin() ); - - return next; + return *_menus.current(); } -NCMenuBar::MenuIterator -NCMenuBar::previousMenu() +void +NCMenuBar::selectNextMenu() { - MenuIterator current = currentMenu(); - - ReverseMenuIterator rbegin; - - if ( current == _menus.end() ) - rbegin = _menus.rbegin(); - else - rbegin = ReverseMenuIterator( current ); - - ReverseMenuIterator previous = findPreviousEnabledMenu( rbegin ); - - if ( previous == _menus.rend() && rbegin != _menus.rbegin() ) - previous = findPreviousEnabledMenu( _menus.rbegin() ); - - if ( previous == _menus.rend() ) - return _menus.end(); - - return find( _menus.begin(), _menus.end(), *previous ); + _menus.setCurrent( _menus.next() ); } -NCMenuBar::MenuIterator -NCMenuBar::findNextEnabledMenu( MenuIterator begin ) +void +NCMenuBar::selectPreviousMenu() { - return find_if( begin, _menus.end(), [](const Menu * menu ) { - return menu->item->isEnabled(); - }); + _menus.setCurrent( _menus.previous() ); } -NCMenuBar::ReverseMenuIterator -NCMenuBar::findPreviousEnabledMenu( ReverseMenuIterator rbegin ) +CyclicContainer<NCMenuBar::Menu>::Iterator +NCMenuBar::findMenuWithHotkey( wint_t key ) { - return find_if( rbegin, _menus.rend(), [](const Menu * menu ) { - return menu->item->isEnabled(); + return std::find_if( _menus.begin(), _menus.end(), [key](Menu * menu) { + return menu->hasHotkey( key ); }); } const NCstyle::StWidget & -NCMenuBar::menuStyle( const Menu * menu ) const +NCMenuBar::menuStyle( const Menu * menu ) { if ( !menu->item->isEnabled() ) return wStyle().getWidget( NC::WSdisabled ); - bool non_active = ( menu != _selectedMenu ); + bool non_active = ( menu != selectedMenu() ); return widgetStyle( non_active ); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/src/NCMenuBar.h new/libyui-ncurses-2.56.1/src/NCMenuBar.h --- old/libyui-ncurses-2.56.0/src/NCMenuBar.h 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/src/NCMenuBar.h 2020-08-17 12:29:15.000000000 +0200 @@ -18,18 +18,17 @@ File: NCMenuBar.h - Author: Stefan Hundhammer <[email protected]> + Author: Jose Iván López <[email protected]> /-*/ + #ifndef NCMenuBar_h #define NCMenuBar_h -#include <vector> - #include <yui/YMenuBar.h> #include "NCWidget.h" - +#include "CyclicContainer.h" class NCMenuBar: public YMenuBar, public NCWidget { @@ -70,6 +69,7 @@ /** * Handle keyboard input. + * Reimplemented from NCWidget. **/ virtual NCursesEvent wHandleInput( wint_t key ); @@ -103,9 +103,17 @@ **/ virtual bool setKeyboardFocus(); + /** + * Handle keyboard input. + * Reimplemented from NCWidget. + **/ virtual NCursesEvent wHandleHotkey( wint_t key ); - virtual bool HasHotkey(int key) ; + /** + * Whether any menu option has the given hot-key . + * Reimplemented from NCWidget. + **/ + virtual bool HasHotkey( int key ) ; protected: @@ -116,17 +124,21 @@ virtual const char * location() const { return "NCMenuBar"; } + /** + * Reimplemented from NCWidget. + **/ virtual void wRedraw(); + /** + * Open a menu dialog + * @return event from the menu dialog + **/ NCursesEvent postMenu(); private: struct Menu; - using MenuIterator = std::vector<Menu *>::iterator; - using ReverseMenuIterator = std::reverse_iterator<MenuIterator>; - friend std::ostream & operator<<( std::ostream & str, const NCMenuBar & obj ); @@ -135,22 +147,46 @@ NCMenuBar & operator=( const NCMenuBar & ); NCMenuBar( const NCMenuBar & ); - NCursesEvent handlePostMenu( const NCursesEvent & event, int selectedIndex ); + /** Helper method to manage the menu dialog event + * @param event event from the menu dialog + * @return a new event + **/ + NCursesEvent handlePostMenu( const NCursesEvent & event ); - void selectMenu( MenuIterator menu ); + /** Currently selected menu. + * @return selected menu + **/ + Menu * selectedMenu(); - MenuIterator currentMenu(); - MenuIterator nextMenu(); - MenuIterator previousMenu(); + /** Select the next enabled menu option. + * @note When there is no selected menu, the first enabled one is selected. + **/ + void selectNextMenu(); - MenuIterator findNextEnabledMenu( MenuIterator begin ); - ReverseMenuIterator findPreviousEnabledMenu( ReverseMenuIterator rbegin ); + /** Select the previous enabled menu. + * @note When there is no selected menu, the last enabled one is selected. + **/ + void selectPreviousMenu(); - const NCstyle::StWidget & menuStyle( const Menu * menu ) const; + /** Find the menu with the given hot-key. + * @param key a hot-key + * @return the menu with the given hot-key. + **/ + CyclicContainer<Menu>::Iterator findMenuWithHotkey( wint_t key ); - std::vector<Menu*> _menus; + /** Style to apply to the given menu + * The style depends on the status of the menu (enabled or disabled). + * @param menu a menu + * @return style to apply + **/ + const NCstyle::StWidget & menuStyle( const Menu * menu ); - Menu* _selectedMenu; + /** Container of menus + * It allows cyclic navigation between the menus. + * Note that this container holds pointers to menus, but it does not own the pointers. The pointers + * are owned by the NCMenuBar object. + **/ + CyclicContainer<Menu> _menus; }; // NCMenuBar diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/src/NCMenuButton.cc new/libyui-ncurses-2.56.1/src/NCMenuButton.cc --- old/libyui-ncurses-2.56.0/src/NCMenuButton.cc 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/src/NCMenuButton.cc 2020-08-17 12:29:15.000000000 +0200 @@ -146,19 +146,20 @@ itemsEnd() ); YUI_CHECK_NEW( dialog ); - int selection = dialog->post(); + NCursesEvent event; + dialog->post( &event ); - if ( selection < 0 ) + YDialog::deleteTopmostDialog(); + + NCursesEvent newEvent = NCursesEvent::none; + + if ( event == NCursesEvent::button ) { - YDialog::deleteTopmostDialog(); - return NCursesEvent::none; + newEvent = NCursesEvent::menu; + newEvent.selection = event.selection; } - NCursesEvent ret = NCursesEvent::menu; - ret.selection = findMenuItem( selection ); - YDialog::deleteTopmostDialog(); - - return ret; + return newEvent; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/src/NCPopupMenu.cc new/libyui-ncurses-2.56.1/src/NCPopupMenu.cc --- old/libyui-ncurses-2.56.0/src/NCPopupMenu.cc 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/src/NCPopupMenu.cc 2020-08-17 12:29:15.000000000 +0200 @@ -22,19 +22,28 @@ /-*/ -#include <algorithm> -#include <iterator> - #define YUILogComponent "ncurses" #include <yui/YUILog.h> #include "NCPopupMenu.h" #include "NCTable.h" +// Helper class that represents a menu item struct NCPopupMenu::Item { YTableItem * tableItem; YMenuItem * menuItem; + + + // Whether the item can be selected + bool isSelectable() const + { + if ( ! menuItem ) + return false; + + return menuItem->isEnabled() && !menuItem->isSeparator(); + } + }; @@ -53,10 +62,6 @@ row[0] = menuItem->label(); row[1] = menuItem->hasChildren() ? "..." : ""; - // TODO - // if (menuItem->isSeparator()) - // row[0] = "---"; - YTableItem *tableItem = new YTableItem( row[0], row[1] ); // yuiDebug() << "Add to std::map: TableItem: " << tableItem << " Menu item: " << item << std::endl; @@ -68,10 +73,10 @@ item->tableItem = tableItem; item->menuItem = menuItem; - _items.push_back( item ); + _items.add( item ); } - selectItem( findNextEnabledItem( _items.begin() ) ); + selectNextItem(); stripHotkeys(); } @@ -92,13 +97,11 @@ { case KEY_RIGHT: { - ItemIterator current = currentItem(); + Item * item = selectedItem(); - if (current != _items.end()) + if ( item ) { - YMenuItem * item = (*current)->menuItem; - - if ( item->hasChildren() ) + if ( item->menuItem->hasChildren() ) event = NCursesEvent::button; else { @@ -119,11 +122,11 @@ break; case KEY_DOWN: - selectItem( nextItem() ); + selectNextItem(); break; case KEY_UP: - selectItem( previousItem() ); + selectPreviousItem(); break; default: @@ -141,24 +144,22 @@ bool again = false; int selection = ( postevent == NCursesEvent::button ) ? getCurrentItem() : -1; - ItemIterator current = currentItem(); + Item * item = selectedItem(); - if ( current == _items.end() ) + if ( ! item ) return false; - YMenuItem * item = (*current)->menuItem; - - yuiDebug() << "Menu item: " << item->label() << std::endl; + yuiDebug() << "Menu item: " << item->menuItem->label() << std::endl; if ( selection != -1 ) { - if ( item->hasChildren() ) + if ( item->menuItem->hasChildren() ) { // post submenu wpos at( ScreenPos() + wpos( selection, inparent.Sze.W - 1 ) ); NCPopupMenu * dialog = new NCPopupMenu( at, - item->childrenBegin(), - item->childrenEnd() ); + item->menuItem->childrenBegin(), + item->menuItem->childrenEnd() ); YUI_CHECK_NEW( dialog ); again = ( dialog->post( &postevent ) == NCursesEvent::CONTINUE ); @@ -168,8 +169,7 @@ else { // store selection - //postevent.detail = menu.itemList()[selection]->getIndex(); - postevent.detail = item->index(); + postevent.selection = item->menuItem; } } @@ -177,89 +177,59 @@ } -NCPopupMenu::ItemIterator -NCPopupMenu::findItem( YTableItem* tableItem ) +NCPopupMenu::Item * NCPopupMenu::selectedItem() { - return find_if(_items.begin(), _items.end(), [tableItem](const Item * item) { - return item->tableItem == tableItem; - }); -} - - -void NCPopupMenu::selectItem( ItemIterator item ) -{ - if ( item != _items.end() ) - { - int index = std::distance(_items.begin(), item); + updateSelectedItem(); - setCurrentItem(index); - } + return *_items.current(); } -NCPopupMenu::ItemIterator NCPopupMenu::currentItem() +void NCPopupMenu::selectNextItem() { - ItemIterator current = _items.end(); - - YTableItem * tableItem = dynamic_cast<YTableItem *> ( getCurrentItemPointer() ); - - if ( tableItem ) - current = findItem(tableItem); - - return current; + selectItem( _items.next() ); } -NCPopupMenu::ItemIterator NCPopupMenu::nextItem() +void NCPopupMenu::selectPreviousItem() { - ItemIterator current = currentItem(); - - if ( current == _items.end() ) - return findNextEnabledItem( _items.begin() ); - - ItemIterator next = findNextEnabledItem( std::next( current, 1 ) ); - - if ( next == _items.end() ) - return findNextEnabledItem( _items.begin() ); - - return next; + selectItem( _items.previous() ); } -NCPopupMenu::ItemIterator NCPopupMenu::previousItem() +void NCPopupMenu::updateSelectedItem() { - ItemIterator current = currentItem(); - - ReverseItemIterator rbegin; - - if ( current == _items.end() ) - rbegin = _items.rbegin(); - else - rbegin = ReverseItemIterator( current ); + YTableItem * tableItem = dynamic_cast<YTableItem *> ( getCurrentItemPointer() ); - ReverseItemIterator previous = findPreviousEnabledItem( rbegin ); + if ( ! tableItem ) + return; - if ( previous == _items.rend() && rbegin != _items.rbegin() ) - previous = findPreviousEnabledItem( _items.rbegin() ); + CyclicContainer<Item>::Iterator newCurrent = findItem( tableItem); - if ( previous == _items.rend() ) - return _items.end(); + if ( newCurrent == _items.end() ) + return; - return find( _items.begin(), _items.end(), *previous ); + if ( _items.current() != newCurrent ) + selectItem( newCurrent ); } -NCPopupMenu::ItemIterator NCPopupMenu::findNextEnabledItem( ItemIterator begin ) +CyclicContainer<NCPopupMenu::Item>::Iterator NCPopupMenu::findItem( YTableItem * tableItem ) { - return find_if( begin, _items.end(), [](const Item * item) { - return item->menuItem->isEnabled() && !item->menuItem->isSeparator(); + return find_if( _items.begin(), _items.end(), [tableItem](Item * item) { + return item->tableItem == tableItem; }); } -NCPopupMenu::ReverseItemIterator NCPopupMenu::findPreviousEnabledItem( ReverseItemIterator rbegin ) +void NCPopupMenu::selectItem( CyclicContainer<Item>::Iterator item ) { - return find_if( rbegin, _items.rend(), [](const Item * item) { - return item->menuItem->isEnabled() && !item->menuItem->isSeparator(); - }); + _items.setCurrent( item ); + + if ( item != _items.end() ) + { + int index = std::distance(_items.begin(), item); + + setCurrentItem(index); + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libyui-ncurses-2.56.0/src/NCPopupMenu.h new/libyui-ncurses-2.56.1/src/NCPopupMenu.h --- old/libyui-ncurses-2.56.0/src/NCPopupMenu.h 2020-08-12 10:34:14.000000000 +0200 +++ new/libyui-ncurses-2.56.1/src/NCPopupMenu.h 2020-08-17 12:29:15.000000000 +0200 @@ -25,9 +25,8 @@ #ifndef NCPopupMenu_h #define NCPopupMenu_h -#include <vector> - #include "NCPopupTable.h" +#include "CyclicContainer.h" class NCPopupMenu : public NCPopupTable @@ -36,24 +35,25 @@ struct Item; - using ItemIterator = std::vector<NCPopupMenu::Item *>::iterator; - using ReverseItemIterator = std::reverse_iterator<ItemIterator>; - NCPopupMenu & operator=( const NCPopupMenu & ); NCPopupMenu( const NCPopupMenu & ); - ItemIterator findItem( YTableItem * tableItem ); - - void selectItem( ItemIterator item ); - - ItemIterator currentItem(); - ItemIterator nextItem(); - ItemIterator previousItem(); - - ItemIterator findNextEnabledItem( ItemIterator begin ); - ReverseItemIterator findPreviousEnabledItem( ReverseItemIterator rbegin ); + Item * selectedItem(); - std::vector<Item *> _items; + void selectNextItem(); + void selectPreviousItem(); + void updateSelectedItem(); + + CyclicContainer<Item>::Iterator findItem( YTableItem * tableItem ); + + void selectItem( CyclicContainer<Item>::Iterator item ); + + /** Container of menu items + * It allows cyclic navigation between the items. + * Note that this container holds pointers to items, but it does not own the pointers. The pointers + * are owned by the NCPopupMenu object. + **/ + CyclicContainer<Item> _items; protected:
