installer/menu.py
f4d17450
 #
 #    Copyright (C) 2015 vmware inc.
 #
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
 
 import curses
 from actionresult import ActionResult
 from action import Action
 
 class Menu(Action):
72832a72
     def __init__(self, starty, maxx, items, height = 0, selector_menu = False, can_navigate_outside = True, horizontal = False, default_selected = 0, save_sel = False, tab_enable = True):
f4d17450
         self.can_navigate_outside = can_navigate_outside
         self.horizontal = horizontal
         self.horizontal_padding = 10
8d282b99
         self.position = default_selected
f4d17450
         self.head_position = 0  #This is the start of showing
         self.items = items
         self.items_strings = []
         self.width = self.lengthen_items()
         self.num_items = len(self.items)
72832a72
         self.save_sel = save_sel
         self.tab_enable=tab_enable
f4d17450
         if height == 0 or height > self.num_items:
             self.height = self.num_items
         else:
             self.height = height
 
         # Check if we need to add a scroll bar
         if self.num_items > self.height:
             self.show_scroll = True
             self.width += 2
         else:
             self.show_scroll = False
 
         # Some calculation to detitmine the size of the scroll filled portion
         self.filled = int(round(self.height * self.height / float(self.num_items)))
         if self.filled == 0:
             self.filled += 1
         for i in [1, 2]:
             if (self.num_items - self.height) >= i and (self.height - self.filled) == (i - 1):
                 self.filled -= 1
 
         # increment the width if it's a selector menu
         self.selector_menu = selector_menu
         if self.selector_menu:
             self.width += 4
0c250142
             self.selected_items = set([])
f4d17450
 
         if self.horizontal:
             menu_win_width = (self.width + self.horizontal_padding) * self.num_items
         else:
             menu_win_width = self.width
 
         self.window = curses.newwin(self.height, menu_win_width)
         self.window.bkgd(' ', curses.color_pair(2))
 
         self.window.keypad(1)
         self.panel = curses.panel.new_panel(self.window)
 
0c250142
         self.panel.move(starty, (maxx - menu_win_width) // 2)
f4d17450
         self.panel.hide()
         curses.panel.update_panels()
 
72832a72
     def can_save_sel(self, can_save_sel):
         self.save_sel = can_save_sel
 
f4d17450
     def lengthen_items(self):
         width = 0
         for item in self.items:
             if len(item[0]) > width:
                 width = len(item[0])
 
         for item in self.items:
             spaces = ''
             for i in range(width - len(item[0])):
                 spaces += ' '
             self.items_strings.append(item[0] + spaces)
         return width + 1
 
 
     def navigate(self, n):
         self.position += n
         if self.position < 0:
             self.position = 0
         elif self.position >= len(self.items):
             self.position = len(self.items)-1
 
         if (self.position >= self.head_position + self.height):
             self.head_position = self.position - self.height + 1
         if (self.position < self.head_position):
             self.head_position = self.position
 
 
     def render_scroll_bar(self):
         if self.show_scroll:
             remaining_above = self.head_position
             remaining_down = self.num_items - self.height - self.head_position#
             
             up = int(round(remaining_above * self.height / float(self.num_items)))
             down = self.height - up - self.filled
 
             if up == 0 and remaining_above > 0:
                 up += 1
                 down -= 1
             if down == 0 and remaining_down > 0:
                 up -= 1
                 down += 1
             if remaining_down == 0 and down != 0:
                 up += down
                 down = 0
 
 
             for index in range(up):
                 self.window.addch(index, self.width - 2, curses.ACS_CKBOARD)
 
             for index in range(self.filled):
                 self.window.addstr(index + up, self.width - 2, ' ', curses.A_REVERSE)
 
             for index in range(down):
                 self.window.addch(index + up + self.filled, self.width - 2, curses.ACS_CKBOARD)
 
     def refresh(self, highligh = True):
         self.window.clear()
         for index, item in enumerate(self.items_strings):
             if (index < self.head_position):
                 continue
             elif (index > self.head_position + self.height - 1):
                 continue
             elif index == self.position:
                 if highligh:
                     mode = curses.color_pair(3)
                 else:
                     mode = curses.color_pair(1)
             else:
                 mode = curses.color_pair(2)
 
             if self.selector_menu:
                 if index in self.selected_items:
                     item = '[x] ' + item
                 else:
                     item = '[ ] ' + item
             if self.horizontal:
0c250142
                 x = self.horizontal_padding // 2 + index * self.horizontal_padding
f4d17450
                 y = 0
             else:
                 x = 0
                 y = index - self.head_position
             self.window.addstr(y, x, item, mode)
 
         self.render_scroll_bar()
 
         self.window.refresh()
         self.panel.top()
         self.panel.show()
         curses.panel.update_panels()
         curses.doupdate()
 
     def hide(self):
         self.panel.hide()
         curses.panel.update_panels()
         curses.doupdate()
 
     def do_action(self):
         while True:
             self.refresh()
 
             key = self.window.getch()
 
             if key in [curses.KEY_ENTER, ord('\n')]:
                 if self.selector_menu:
                     # send the selected indexes
                     result = self.items[self.position][1](self.selected_items)
                 else:
                     result = self.items[self.position][1](self.items[self.position][2])
                 if result.success:
                     self.hide()
                     return result
 
             if key in [ord(' ')] and self.selector_menu:
                 if self.position in self.selected_items:
                     self.selected_items.remove(self.position)
                 else:
                     self.selected_items.add(self.position)
             elif key in [ord('\t')] and self.can_navigate_outside:
72832a72
                 if not self.tab_enable:
                     continue
f4d17450
                 self.refresh(False)
72832a72
                 if self.save_sel:
                     return ActionResult(False, {'diskIndex': self.position})
                 else:
                     return ActionResult(False, None)
f4d17450
             
             elif key == curses.KEY_UP or key == curses.KEY_LEFT:
72832a72
                 if not self.tab_enable and key==curses.KEY_LEFT:
                     if self.save_sel:
                         return ActionResult(False, {'diskIndex': self.position, 'direction':-1})
                     elif self.selector_menu:
                         result = self.items[self.position][1](self.selected_items)
                     else:
                         result = self.items[self.position][1](self.items[self.position][2])
                     return ActionResult(False, {'direction': -1})
f4d17450
                 self.navigate(-1)
 
             elif key == curses.KEY_DOWN or key == curses.KEY_RIGHT:
72832a72
                 if not self.tab_enable and key==curses.KEY_RIGHT:
                     if self.save_sel:
                         return ActionResult(False, {'diskIndex': self.position, 'direction':1})
                     else:
                         return ActionResult(False, {'direction': 1})
f4d17450
                 self.navigate(1)
 
             elif key == curses.KEY_NPAGE:
                 self.navigate(self.height)
 
             elif key == curses.KEY_PPAGE:
                 self.navigate(-self.height)
 
             elif key == curses.KEY_HOME:
                 self.navigate(-self.position)