import curses import locale class Box: def __init__(self, gui, window, x, y, w, h, color): self.gui = gui self.window = window self.x = x self.y = y self.w = w self.h = h self.color = color def draw(self): self.gui.box(self.window, self.x, self.y, self.w, self.h, self.color) class TextBox: def __init__(self, gui, window, x, y, w, h, color, text, text_color, selected_color): self.gui = gui self.window = window self.x = x self.y = y self.w = w self.h = h self.scroll_index = 0 self.selected_index = 0 self.text = text self.text_color = text_color self.color = color self.selected_color = selected_color def scroll_up(self): if self.selected_index > 0: self.selected_index = self.selected_index - 1 if self.selected_index < self.scroll_index: self.scroll_index = self.scroll_index - 1 self.draw() def scroll_down(self): if self.selected_index < len(self.text) - 1: self.selected_index = self.selected_index + 1 if self.selected_index > self.scroll_index + (self.h - 2) - 1: self.scroll_index = self.scroll_index + 1 self.draw() def at_top(self): return self.selected_index == 0 def at_bottom(self): return self.selected_index == len(self.text) - 1 def scroll_top(self): self.selected_index = 0 self.scroll_index = 0 self.draw() def scroll_bottom(self): self.selected_index = len(self.text) - 1 self.scroll_index = len(self.text) - (self.h - 2) self.scroll_index = self.scroll_index if self.scroll_index > 0 else 0 self.draw() def draw(self): self.gui.box(self.window, self.x, self.y, self.w, self.h, self.color) for (i, l) in enumerate(self.text[self.scroll_index:self.scroll_index + self.h - 2]): if len(l) > self.w - 2: l = l[:self.w - 5] + "..." l = l.ljust(self.w - 2) self.window.addstr(self.y + 1 + i, self.x + 1, l, self.text_color if self.selected_index != self.scroll_index + i else self.selected_color) for j in xrange(i + 1, self.h - 2): self.window.addstr(self.y + 1 + j, self.x + 1, " " * (self.w - 2), self.text_color if self.selected_index != self.scroll_index + j else self.selected_color) self.gui.vscrollbar(self.window, self.x + self.w, self.y, self.h, self.selected_index / float(len(self.text)), self.gui.gray(1)) class Gui: GRAY_BASE = 50 GRAYS = 50 BLACK = 1 WHITE = 2 BLUE = 3 RED = 4 GREEN = 5 COLOR_BLACK = 16 COLOR_WHITE = 17 COLOR_BLUE = 18 COLOR_RED = 19 COLOR_GREEN = 20 def __init__(self, no_delay=True): self.start(no_delay) def refresh(self): self.window.refresh() def start(self, no_delay): self.window = curses.initscr() curses.start_color() curses.use_default_colors() curses.noecho() curses.cbreak() curses.curs_set(0) self.window.nodelay(no_delay) self.init_colors() self.window.bkgd(curses.color_pair(self.WHITE)) locale.setlocale(locale.LC_ALL, '') # set your locale self.code = locale.getpreferredencoding() def stop(self): curses.nocbreak(); curses.echo() curses.endwin() def get_key(self): return self.window.getch() def init_colors(self): if curses.has_colors() and curses.can_change_color(): curses.init_color(self.COLOR_BLACK, 0, 0, 0) curses.init_color(self.COLOR_WHITE, 1000, 1000, 1000) curses.init_color(self.COLOR_BLUE, 0, 0, 1000) curses.init_color(self.COLOR_RED, 1000, 0, 0) curses.init_color(self.COLOR_GREEN, 0, 1000, 0) for i in xrange(0, self.GRAYS): curses.init_color( self.GRAY_BASE + i, i * 1000 / (self.GRAYS - 1), i * 1000 / (self.GRAYS - 1), i * 1000 / (self.GRAYS - 1) ) curses.init_pair( self.GRAY_BASE + i, self.GRAY_BASE + i, self.COLOR_BLACK ) else: self.COLOR_BLACK = curses.COLOR_BLACK self.COLOR_WHITE = curses.COLOR_WHITE self.COLOR_BLUE = curses.COLOR_BLUE self.COLOR_RED = curses.COLOR_RED self.COLOR_GREEN = curses.COLOR_GREEN for i in xrange(0, self.GRAYS): curses.init_pair( self.GRAY_BASE + i, self.COLOR_WHITE, self.COLOR_BLACK ) curses.init_pair(self.BLACK, self.COLOR_BLACK, self.COLOR_BLACK) curses.init_pair(self.WHITE, self.COLOR_WHITE, self.COLOR_BLACK) curses.init_pair(self.BLUE, self.COLOR_BLUE, self.COLOR_BLACK) curses.init_pair(self.RED, self.COLOR_RED, self.COLOR_BLACK) curses.init_pair(self.GREEN, self.COLOR_GREEN, self.COLOR_BLACK) def gray(self, scale): if curses.can_change_color(): return curses.color_pair(self.GRAY_BASE + int(round(scale * (self.GRAYS - 1)))) else: return curses.color_pair(self.WHITE) def box(self, window, x, y, w, h, color): for i in xrange(1, w - 1): window.addch(y, x + i, curses.ACS_HLINE, color) window.addch(y + h - 1, x + i, curses.ACS_HLINE, color) for i in xrange(1, h - 1): window.addch(y + i, x, curses.ACS_VLINE, color) window.addch(y + i, x + w - 1, curses.ACS_VLINE, color) window.addch(y, x, curses.ACS_ULCORNER, color) window.addch(y, x + w - 1, curses.ACS_URCORNER, color) window.addch(y + h - 1, x, curses.ACS_LLCORNER, color) window.addch(y + h - 1, x + w - 1, curses.ACS_LRCORNER, color) def bracket(self, window, x, y, h, color): for i in xrange(1, h - 1): window.addch(y + i, x, curses.ACS_VLINE, color) window.addch(y, x, curses.ACS_ULCORNER, color) window.addch(y + h - 1, x, curses.ACS_LLCORNER, color) def vaddstr(self, window, x, y, s, color): for i in xrange(0, len(s)): window.addch(y + i, x, s[i], color) def vscrollbar(self, window, x, y, height, progress, color): if height < 3: return self.vaddstr(window, x, y, "-" + " " * (height - 2) + "-", color) window.addch(int(y + 1 + progress * (height - 2)), x, "|", color) def hscrollbar(self, window, x, y, width, color): window.addstr(y, x, "}", color) window.addstr(y + height - 1, x, '}', color) window.addch(y, int(x + 1 + progress * (width - 2)), curses.ACS_BLOCK, color)