# HG changeset patch # User Radek Brich # Date 1318086967 -7200 # Node ID 8553a6bd2d8292cf43476ebc8591f887667d8d58 # Parent 472a753664f90b3587320b2edc16d0840e765fdd Add TableView plus demo. diff -r 472a753664f9 -r 8553a6bd2d82 demo_tableview.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demo_tableview.py Sat Oct 08 17:16:07 2011 +0200 @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import locale +locale.setlocale(locale.LC_ALL, '') + +from tuikit import Application +from tuikit.layout import VerticalLayout +from tuikit.tableview import TableView, TableModel + + +class MyApplication(Application): + def __init__(self): + Application.__init__(self) + self.top.connect('keypress', self.globalkeypress) + + data = [] + for y in range(100): + row = [str(y)] + for x in range(10): + row.append('r{}:c{}'.format(y, x)) + data.append(row) + model = TableModel(data) + + view = TableView(model) + view.addcolumn(header=True, expand=False, sizereq=5) + for x in range(10): + view.addcolumn(title='head'+str(x)) + + self.top.add(view, expand=True, fill=True) + + vert = VerticalLayout() + self.top.layout(vert) + + def globalkeypress(self, keyname, char): + if keyname == 'escape': + self.terminate() + + +if __name__ == '__main__': + app = MyApplication() + app.start() + diff -r 472a753664f9 -r 8553a6bd2d82 docs/index.rst --- a/docs/index.rst Fri Oct 07 12:36:14 2011 +0200 +++ b/docs/index.rst Sat Oct 08 17:16:07 2011 +0200 @@ -17,6 +17,7 @@ focus redraw colors + tableview .. inheritance-diagram:: tuikit.application tuikit.eventsource diff -r 472a753664f9 -r 8553a6bd2d82 docs/tableview.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tableview.rst Sat Oct 08 17:16:07 2011 +0200 @@ -0,0 +1,11 @@ +TableView +========= + +.. toctree:: + :maxdepth: 3 + :titlesonly: + +.. automodule:: tuikit.tableview + :members: + :show-inheritance: + diff -r 472a753664f9 -r 8553a6bd2d82 tuikit/__init__.py --- a/tuikit/__init__.py Fri Oct 07 12:36:14 2011 +0200 +++ b/tuikit/__init__.py Sat Oct 08 17:16:07 2011 +0200 @@ -13,6 +13,7 @@ from tuikit.menubar import MenuBar from tuikit.pager import Pager from tuikit.scrollbar import VScrollbar +from tuikit.tableview import TableModel, TableView from tuikit.textedit import TextEdit from tuikit.treeview import TreeNode, TreeModel, TreeView from tuikit.widget import Widget diff -r 472a753664f9 -r 8553a6bd2d82 tuikit/application.py --- a/tuikit/application.py Fri Oct 07 12:36:14 2011 +0200 +++ b/tuikit/application.py Sat Oct 08 17:16:07 2011 +0200 @@ -137,6 +137,7 @@ def applytheme(self): screen = self.screen screen.setcolor('normal', 'white on black') + screen.setcolor('strong', 'white on black, bold') screen.setcolor('active', 'black on cyan') screen.setcolor('window:normal', 'white on blue') screen.setcolor('window:controls', 'white on blue, bold') diff -r 472a753664f9 -r 8553a6bd2d82 tuikit/backend_curses.py --- a/tuikit/backend_curses.py Fri Oct 07 12:36:14 2011 +0200 +++ b/tuikit/backend_curses.py Sat Oct 08 17:16:07 2011 +0200 @@ -513,7 +513,7 @@ return [('keypress', 'Unknown', None)] if keyname == 'mouse': - return self.process_xterm_mouse() + return self.process_xterm_mouse() return [('keypress', keyname, None)] diff -r 472a753664f9 -r 8553a6bd2d82 tuikit/tableview.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tuikit/tableview.py Sat Oct 08 17:16:07 2011 +0200 @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- + +import math + +from tuikit.widget import EventSource, Widget +from tuikit.common import Coords + + +class TableModel(EventSource): + def __init__(self, list_of_lists): + EventSource.__init__(self) + self.addevents('change') + self.data = list_of_lists + + def getcount(self): + '''Get number of rows.''' + return len(self.data) + + def getrows(self, begin, end): + '''Get rows from begin to end, including begin, excluding end.''' + return self.data[begin:end] + + def update(self, row, col, val): + self.data[row][col] = val + + +class Column: + + '''Columns description.''' + + def __init__(self, title='', expand=True, sizereq=1, + header=False, readonly=False, maxlength=None): + '''Create column with default values.''' + + self.title = title + '''Column title''' + + self.expand = expand + '''Use free space?''' + + self.sizereq = sizereq + '''Size request. Meaning depends on value of expand: + + When false, sizereq is number of characters. + When true, sizereq is relative size ratio. + + ''' + + self.size = 0 + '''Computed size of column.''' + + self.header = header + '''Is this header column? (bold, readonly)''' + + self.readonly = readonly + '''Allow edit?''' + + self.maxlength = maxlength + '''Maximum length of value (for EditField).''' + + +class TableView(Widget): + def __init__(self, model=None, width=20, height=20): + Widget.__init__(self, width, height) + + # model + self._model = None + self.setmodel(model) + + self.columns = [] + self.spacing = 1 + + self.offset = Coords() + + self.connect('draw', self.on_draw) + self.connect('keypress', self.on_keypress) + + def getmodel(self): + return self._model + + def setmodel(self, value): + if self._model: + self._model.disconnect('change', self.redraw) + self._model = value + if self._model: + self._model.connect('change', self.redraw) + + model = property(getmodel, setmodel) + + def addcolumn(self, *args, **kwargs): + for col in args: + self.columns.append(col) + if len(args) == 0: + col = Column(**kwargs) + self.columns.append(col) + + def compute_column_sizes(self): + total_space = self.size.w - self.spacing * len(self.columns) + no_expand_cols = [col for col in self.columns if not col.expand] + no_expand_size = sum([col.sizereq for col in no_expand_cols]) + expand_cols = [col for col in self.columns if col.expand] + expand_num = len(expand_cols) + expand_size = total_space - no_expand_size + + # compute size of cols without expand + for col in no_expand_cols: + col.size = col.sizereq + + # compute size of cols with expand + if no_expand_size > total_space + expand_num: + for col in expand_cols: + col.size = 1 + else: + total_req = sum([col.sizereq for col in expand_cols]) + remaining_space = 0. + for col in expand_cols: + frac, intp = math.modf(expand_size * col.sizereq / total_req) + col.size = int(intp) + remaining_space += frac + if remaining_space > 0.99: + remaining_space -= 1. + col.size += 1 + + def draw_head(self, screen, x, y): + screen.pushcolor('strong') + for col in self.columns: + screen.puts(x, y, col.title[:col.size]) + x += col.size + self.spacing + screen.popcolor() + + def draw_row(self, screen, x, y, row): + for col, data in zip(self.columns, row): + if col.header: + screen.pushcolor('strong') + screen.puts(x, y, data[:col.size]) + if col.header: + screen.popcolor() + x += col.size + self.spacing + + def on_draw(self, screen, x, y): + screen.pushcolor('normal') + head_size = 1 + numrows = min(self.model.getcount() - self.offset.y, self.size.h - head_size) + rows = self.model.getrows(self.offset.y, self.offset.y + numrows) + self.compute_column_sizes() + self.draw_head(screen, x, y) + y += head_size + for row in rows: + self.draw_row(screen, x, y, row) + y += 1 + screen.popcolor() + + def on_keypress(self, keyname, char): + if keyname: + if keyname == 'up': self.move_up() + if keyname == 'down': self.move_down() + if keyname == 'left': self.move_left() + if keyname == 'right': self.move_right() + self.redraw() +