Add TableView plus demo.
# -*- 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()