diff options
Diffstat (limited to 'src/windows/list.py')
-rw-r--r-- | src/windows/list.py | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/windows/list.py b/src/windows/list.py new file mode 100644 index 00000000..3cfb8af5 --- /dev/null +++ b/src/windows/list.py @@ -0,0 +1,237 @@ +""" +Windows relevant for the listing tabs, not much else +""" + +import logging +log = logging.getLogger(__name__) + +import curses + +from . import Win, g_lock +from theming import to_curses_attr, get_theme + + +class ListWin(Win): + """ + A list (with no depth, so not for the roster) that can be + scrolled up and down, with one selected line at a time + """ + def __init__(self, columns, with_headers=True): + Win.__init__(self) + self._columns = columns # a dict {'column_name': tuple_index} + self._columns_sizes = {} # a dict {'column_name': size} + self.sorted_by = (None, None) # for example: ('name', '↑') + self.lines = [] # a list of dicts + self._selected_row = 0 + self._starting_pos = 0 # The column number from which we start the refresh + + @property + def pos(self): + if len(self.lines) > self.height: + return len(self.lines) + else: + return 0 + + def empty(self): + """ + emtpy the list and reset some important values as well + """ + self.lines = [] + self._selected_row = 0 + self._starting_pos = 0 + + def resize_columns(self, dic): + """ + Resize the width of the columns + """ + self._columns_sizes = dic + + def sort_by_column(self, col_name, asc=True): + """ + Sort the list by the given column, ascendant or descendant + """ + if not col_name: + return + elif asc: + self.lines.sort(key=lambda x: x[self._columns[col_name]]) + else: + self.lines.sort(key=lambda x: x[self._columns[col_name]], + reverse=True) + self.refresh() + curses.doupdate() + + def add_lines(self, lines): + """ + Append some lines at the end of the list + """ + if not lines: + return + self.lines.extend(lines) + + def set_lines(self, lines): + """ + Set the lines to another list + """ + if not lines: + return + self.lines = lines + + def get_selected_row(self): + """ + Return the tuple representing the selected row + """ + if self._selected_row is not None and self.lines: + return self.lines[self._selected_row] + return None + + def refresh(self): + log.debug('Refresh: %s', self.__class__.__name__) + with g_lock: + self._win.erase() + lines = self.lines[self._starting_pos:self._starting_pos+self.height] + for y, line in enumerate(lines): + x = 0 + for col in self._columns.items(): + try: + txt = line[col[1]] or '' + except KeyError: + txt = '' + size = self._columns_sizes[col[0]] + txt += ' ' * (size-len(txt)) + if not txt: + continue + if line is self.lines[self._selected_row]: + self.addstr(y, x, txt[:size], to_curses_attr(get_theme().COLOR_INFORMATION_BAR)) + else: + self.addstr(y, x, txt[:size]) + x += size + self._refresh() + + def move_cursor_down(self): + """ + Move the cursor Down + """ + if not self.lines: + return + if self._selected_row < len(self.lines) - 1: + self._selected_row += 1 + while self._selected_row >= self._starting_pos + self.height: + self._starting_pos += self.height // 2 + if self._starting_pos < 0: + self._starting_pos = 0 + return True + + def move_cursor_up(self): + """ + Move the cursor Up + """ + if not self.lines: + return + if self._selected_row > 0: + self._selected_row -= 1 + while self._selected_row < self._starting_pos: + self._starting_pos -= self.height // 2 + return True + + def scroll_down(self): + if not self.lines: + return + self._selected_row += self.height + if self._selected_row > len(self.lines) - 1: + self._selected_row = len(self.lines) -1 + while self._selected_row >= self._starting_pos + self.height: + self._starting_pos += self.height // 2 + if self._starting_pos < 0: + self._starting_pos = 0 + return True + + def scroll_up(self): + if not self.lines: + return + self._selected_row -= self.height + 1 + if self._selected_row < 0: + self._selected_row = 0 + while self._selected_row < self._starting_pos: + self._starting_pos -= self.height // 2 + return True + +class ColumnHeaderWin(Win): + """ + A class displaying the column's names + """ + def __init__(self, columns): + Win.__init__(self) + self._columns = columns + self._columns_sizes = {} + self._column_sel = '' + self._column_order = '' + self._column_order_asc = False + + def resize_columns(self, dic): + self._columns_sizes = dic + + def get_columns(self): + return self._columns + + def refresh(self): + log.debug('Refresh: %s', self.__class__.__name__) + with g_lock: + self._win.erase() + x = 0 + for col in self._columns: + txt = col + if col in self._column_order: + if self._column_order_asc: + txt += get_theme().CHAR_COLUMN_ASC + else: + txt += get_theme().CHAR_COLUMN_DESC + #⇓⇑↑↓⇧⇩▲▼ + size = self._columns_sizes[col] + txt += ' ' * (size-len(txt)) + if col in self._column_sel: + self.addstr(0, x, txt, to_curses_attr(get_theme().COLOR_COLUMN_HEADER_SEL)) + else: + self.addstr(0, x, txt, to_curses_attr(get_theme().COLOR_COLUMN_HEADER)) + x += size + self._refresh() + + def sel_column(self, dic): + self._column_sel = dic + + def get_sel_column(self): + return self._column_sel + + def set_order(self, order): + self._column_order = self._column_sel + self._column_order_asc = order + + def get_order(self): + if self._column_sel == self._column_order: + return self._column_order_asc + else: + return False + + def sel_column_left(self): + if self._column_sel in self._columns: + index = self._columns.index(self._column_sel) + if index > 1: + index = index -1 + else: + index = 0 + else: + index = 0 + self._column_sel = self._columns[index] + self.refresh() + + def sel_column_right(self): + if self._column_sel in self._columns: + index = self._columns.index(self._column_sel) + if index < len(self._columns)-2: + index = index +1 + else: + index = len(self._columns) -1 + else: + index = len(self._columns) - 1 + self._column_sel = self._columns[index] + self.refresh() + |