libyui-ncurses  2.57.2
NCPopupMenu.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: NCPopupMenu.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 
25 #define YUILogComponent "ncurses"
26 #include <yui/YUILog.h>
27 #include "NCPopupMenu.h"
28 #include "NCTable.h"
29 
30 
31 // Helper class that represents a menu item
33 {
34  YTableItem * tableItem;
35  YMenuItem * menuItem;
36 
37 
38  // Whether the item can be selected
39  bool isSelectable() const
40  {
41  if ( ! menuItem )
42  return false;
43 
44  return menuItem->isEnabled() && !menuItem->isSeparator();
45  }
46 
47 };
48 
49 
50 NCPopupMenu::NCPopupMenu( const wpos & at, YItemIterator begin, YItemIterator end )
51  : NCPopupTable( at )
52  , _items()
53 {
54  std::vector<std::string> row( 2 );
55  createList( row );
56 
57  for ( YItemIterator it = begin; it != end; ++it )
58  {
59  YMenuItem * menuItem = dynamic_cast<YMenuItem *>( *it );
60  YUI_CHECK_PTR( menuItem );
61 
62  if ( ! menuItem->isVisible() )
63  continue;
64 
65  row[0] = menuItem->label();
66  row[1] = menuItem->hasChildren() ? "..." : "";
67 
68  YTableItem *tableItem = new YTableItem( row[0], row[1] );
69  // yuiDebug() << "Add to std::map: TableItem: " << tableItem << " Menu item: " << item << std::endl;
70 
71  NCTableLine::STATE state = menuItem->isEnabled() ? NCTableLine::S_NORMAL : NCTableLine::S_DISABLED;
72 
73  addItem( tableItem, state );
74 
75  Item * item = new Item();
76  item->tableItem = tableItem;
77  item->menuItem = menuItem;
78 
79  _items.add( item );
80  }
81 
82  selectNextItem();
83 
84  stripHotkeys();
85 }
86 
87 
88 NCPopupMenu::~NCPopupMenu()
89 {
90  for (Item * item : _items)
91  delete item;
92 }
93 
94 
95 NCursesEvent NCPopupMenu::wHandleInput( wint_t ch )
96 {
97  NCursesEvent event;
98 
99  switch ( ch )
100  {
101  case KEY_RIGHT:
102  {
103  Item * item = selectedItem();
104 
105  if ( item )
106  {
107  if ( item->menuItem->hasChildren() )
108  event = NCursesEvent::button;
109  else
110  {
111  event = NCursesEvent::key;
112  event.keySymbol = "CursorRight";
113  }
114  }
115 
116  break;
117  }
118 
119  case KEY_LEFT:
120  event = NCursesEvent::key;
121 
122  event.keySymbol = "CursorLeft";
123  event.detail = NCursesEvent::CONTINUE;
124 
125  break;
126 
127  case KEY_DOWN:
128  selectNextItem();
129  break;
130 
131  case KEY_UP:
132  selectPreviousItem();
133  break;
134 
135  case KEY_BACKSPACE:
136  event = NCursesEvent::key;
137  event.keySymbol = "BackSpace";
138  break;
139 
140  case KEY_SPACE:
141  case KEY_RETURN:
142  {
143  Item * item = selectedItem();
144 
145  if ( item && ! item->menuItem->hasChildren() )
146  {
147  event = NCursesEvent::SelectionChanged;
148  event.detail = item->tableItem->index();
149  }
150  else
151  {
152  event = NCPopup::wHandleInput( ch );
153  }
154  }
155  break;
156 
157  default:
158  event = wHandleHotkey( ch );
159 
160  if ( event == NCursesEvent::none )
161  event = NCPopup::wHandleInput( ch );
162 
163  break;
164  }
165 
166  return event;
167 }
168 
169 
170 NCursesEvent NCPopupMenu::wHandleHotkey( wint_t key )
171 {
172  NCursesEvent event = NCPopupTable::wHandleHotkey( key );
173 
174  if ( event == NCursesEvent::none )
175  {
176  event = NCursesEvent::key;
177  event.keySymbol = "Hotkey";
178  event.detail = key;
179  }
180 
181  return event;
182 }
183 
184 
185 bool NCPopupMenu::postAgain()
186 {
187  // dont mess up postevent.detail here
188  bool again = false;
189  int selection = ( postevent == NCursesEvent::button ) ? getCurrentItem() : -1;
190 
191  Item * item = selectedItem();
192 
193  if ( ! item )
194  return false;
195 
196  yuiDebug() << "Menu item: " << item->menuItem->label() << std::endl;
197 
198  if ( selection != -1 )
199  {
200  if ( item->menuItem->hasChildren() )
201  {
202  // post submenu
203  wpos at( ScreenPos() + wpos( selection, inparent.Sze.W - 1 ) );
204  NCPopupMenu * dialog = new NCPopupMenu( at,
205  item->menuItem->childrenBegin(),
206  item->menuItem->childrenEnd() );
207  YUI_CHECK_NEW( dialog );
208 
209  again = ( dialog->post( &postevent ) == NCursesEvent::CONTINUE );
210 
211  YDialog::deleteTopmostDialog();
212  }
213  else
214  {
215  // store selection
216  postevent.selection = item->menuItem;
217  }
218  }
219 
220  return again;
221 }
222 
223 
224 NCPopupMenu::Item * NCPopupMenu::selectedItem()
225 {
226  updateSelectedItem();
227 
228  return *_items.current();
229 }
230 
231 
232 void NCPopupMenu::selectNextItem()
233 {
234  selectItem( _items.next() );
235 }
236 
237 
238 void NCPopupMenu::selectPreviousItem()
239 {
240  selectItem( _items.previous() );
241 }
242 
243 
244 void NCPopupMenu::updateSelectedItem()
245 {
246  YTableItem * tableItem = dynamic_cast<YTableItem *> ( getCurrentItemPointer() );
247 
248  if ( ! tableItem )
249  return;
250 
251  CyclicContainer<Item>::Iterator newCurrent = findItem( tableItem);
252 
253  if ( newCurrent == _items.end() )
254  return;
255 
256  if ( _items.current() != newCurrent )
257  selectItem( newCurrent );
258 }
259 
260 
261 CyclicContainer<NCPopupMenu::Item>::Iterator NCPopupMenu::findItem( YTableItem * tableItem )
262 {
263  return find_if( _items.begin(), _items.end(), [tableItem](Item * item) {
264  return item->tableItem == tableItem;
265  });
266 }
267 
268 
269 void NCPopupMenu::selectItem( CyclicContainer<Item>::Iterator item )
270 {
271  _items.setCurrent( item );
272 
273  if ( item != _items.end() )
274  {
275  int index = std::distance(_items.begin(), item);
276 
277  setCurrentItem(index);
278  }
279 }
wpos
Screen position pair in the order line, column: (L, C)
Definition: position.h:110
NCPopupMenu::Item
Definition: NCPopupMenu.cc:33
NCursesEvent
Definition: NCurses.h:73
CyclicContainer
Container class that allows cyclic navigation between its elements by moving to the next/previous ele...
Definition: CyclicContainer.h:40
NCPopupTable
Definition: NCPopupTable.h:41
NCPopupMenu
Definition: NCPopupMenu.h:33