#!/usr/bin/python import copy import curses import gettext import locale import os import sys from curses.ascii import ctrl from copy import copy class BaseScreen(object): def __init__(self, main_win): self.instance = "" self.main_win = main_win self.center_win = self.main_win.central_area self._win_size = self.center_win.window.getmaxyx() self.redraw_keys = [InnerWindow.REPAINT_KEY] def get_win_size_y(self): return self._win_size[0] - self.center_win.border_size[0] * 2 def get_win_size_x(self): return self._win_size[1] - self.center_win.border_size[1] * 2 win_size_x = property(get_win_size_x) win_size_y = property(get_win_size_y) def show(self): try: self.main_win.clear() self._show() self.main_win.do_update() return self.validate_loop() except: raise def validate_loop(self): continue_validate = True while continue_validate: pass return next_screen def no_action(input_key): print >> sys.stderr, "no_action called" return input_key class InnerWindow(object): USE_ESC = False UPDATE_FOOTER = False BKGD_CHAR = ord(' ') REPAINT_KEY = ord(ctrl('L')) def no_ut_refresh(self, abs_y=None, abs_x=None): self.window.noutrefresh() def set_color(self, color): if color is None: return self.window.bkgd(InnerWindow.BKGD_CHAR, color) self.no_ut_refresh() for win in self.more_windows: win.bkgd(InnerWindow.BKGD_CHAR, color) win.noutrefresh() def _init_win(self, parent): self.window = curses.newwin(self.area.lines, self.area.columns, self.area.y_loc, self.area.x_loc) self.window.keypad(1) self.window.leaveok(0) def __init__(self, area, window=None, at_index=None, add_obj=True, color_theme=None, border_size=(0, 0), data_obj=None): self.border_size = border_size self.selectable = True self.data_obj = data_obj self.objects = [] self.all_objects = [] self.more_windows = [] self.active_object = None self.key_dict = None self._init_key_dict() self.area = copy(area) self.color_theme = color_theme if isinstance(window, InnerWindow): self.latest_yx = window.latest_yx window.add_object(self, at_index=at_index, selectable=add_obj) self.color_theme = window.color_theme else: self.latest_yx = (0, 0) self.window = None self._init_win(window) self.color = self.color_theme.default self.highlight_color = self.color_theme.list_field self.set_color(self.color) def make_active(self): self.set_color(self.highlight_color) if self.objects: if self.active_object is None: self.active_object = 0 self.objects[self.active_object].make_active() def activate_object(self, index=0, loop=False, jump=False): index = self.objects.index(index) self.objects[index].make_active() self.no_ut_refresh() def add_text(self, text, start_y=0, start_x=0, max_chars=None): win_y, win_x = self.window.getmaxyx() max_x = self.window.getmaxyx()[1] - self.border_size[1] start_x += self.border_size[1] abs_max_chars = max_x - start_x if max_chars is None: max_chars = abs_max_chars else: max_chars = min(max_chars, abs_max_chars) self.window.addstr(start_y, start_x, text) self.no_ut_refresh() def add_object(self, obj, at_index=None, selectable=True): if at_index is None: at_index = len(self.objects) if selectable: self.objects.insert(at_index, obj) self.all_objects.append(obj) def clear(self): for obj in self.all_objects: obj.clear() self.objects = [] self.all_objects = [] self.active_object = None self.window.erase() self.set_color(self.color) self._init_key_dict() def _init_key_dict(self): self.key_dict = {} self.key_dict[curses.KEY_LEFT] = no_action self.key_dict[curses.KEY_RIGHT] = no_action self.key_dict[InnerWindow.REPAINT_KEY] = no_action def get_active_object(self): if self.active_object is not None: return self.objects[self.active_object] else: return None class ColorTheme(object): def __init__(self): has_colors = curses.has_colors() curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) self.default = curses.color_pair(1) | curses.A_BOLD curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_CYAN) self.list_field = curses.color_pair(5) | curses.A_BOLD class MainWindow(object): def __init__(self, initscr): self.theme = ColorTheme() self.initscr = initscr self.central_area = None self.error_line = None self._active_win = None self.reset() def do_update(self): curses.doupdate() def reset(self): window_size = self.initscr.getmaxyx() win_size_y = window_size[0] win_size_x = window_size[1] central_win_area = WindowArea(win_size_y - 4, win_size_x - 2, 2, 1) self.central_area = InnerWindow(central_win_area, border_size=(0, 2), color_theme=self.theme) self._active_win = self.central_area def clear(self): self.central_area.clear() class ListItem(InnerWindow): def __init__(self, area, window=None, text="", selected=False, select_text="", centered=False): color_theme = window.color_theme color = color_theme.default highlight_color = color_theme.list_field self._active = False self._selected = selected self._text = text self._select_text = select_text super(ListItem, self).__init__(area, window=window, color_theme=color_theme) if self.selected: self.set_text(select_text, centered) else: self.set_text(text, centered) @property def selected(self): return self._selected def set_text(self, text, centered=False): self.window.clear() self.add_text(text, max_chars=(self.window.getmaxyx()[1] - 1)) class UserScreen(BaseScreen): def __init__(self, main_win): super(UserScreen, self).__init__(main_win) self.max_text_len = (self.win_size_x - 14) / 2 max_field = 14 self.text_len = min(max_field + 1, self.max_text_len) self.list_area = WindowArea(1, self.text_len, 0, 2) self.root_pass_list = None def _show(self): self.list_area.y_loc = 3 self.root_pass_list = ListItem(self.list_area, window=self.center_win, text="Root password:") self.main_win.do_update() self.center_win.activate_object(self.root_pass_list) class WindowArea(object): def __init__(self, lines=None, columns=None, y_loc=None, x_loc=None): self.lines = lines self.columns = columns self.y_loc = y_loc self.x_loc = x_loc if __name__ == "__main__": initscr = curses.initscr() if curses.has_colors(): curses.start_color() main_win = MainWindow(initscr) user_screen = UserScreen(main_win) try: user_screen.show() except: pass