mirror of
https://github.com/evennia/evennia.git
synced 2026-04-01 13:37:17 +02:00
Reworked EvTable to use internal EvColumn objects. This allows a new method on EvTable. Columns with a set width will not be affected by auto-balancing, allowing for mixing fixed and auto-balancing columns as suggested in #550. Changed EvTable keywords involving characters to consistently end with _char, such as corner_top_left -> corner_top_left_char.
This commit is contained in:
parent
fd7bb29505
commit
8b8fbe8101
2 changed files with 247 additions and 109 deletions
|
|
@ -1,11 +1,6 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
Mudform - a way to create advanced ascii forms
|
||||
|
||||
WARNING: UNDER DEVELOPMENT. Evform does currently NOT support
|
||||
colour ANSI markers in the table. Non-colour forms should
|
||||
work fully (so make issues if they don't).
|
||||
|
||||
EvForm - a way to create advanced ascii forms
|
||||
|
||||
This is intended for creating advanced ascii game forms, such as a
|
||||
large pretty character sheet or info document.
|
||||
|
|
@ -14,7 +9,7 @@ The system works on the basis of a readin template that is given in a
|
|||
separate python file imported into the handler. This file contains
|
||||
some optional settings and a string mapping out the form. The template
|
||||
has markers in it to denounce fields to fill. The markers map the
|
||||
absolute size of the field and will be filled with an evtable.Cell
|
||||
absolute size of the field and will be filled with an evtable.EvCell
|
||||
object when displaying the form.
|
||||
|
||||
Note, when printing examples with ANSI color, you need to wrap
|
||||
|
|
@ -119,7 +114,7 @@ This produces the following result:
|
|||
| | |
|
||||
------------------------------------------------
|
||||
|
||||
The marked forms have been replaced with Cells of text and with
|
||||
The marked forms have been replaced with EvCells of text and with
|
||||
EvTables. The form can be updated by simply re-applying form.map()
|
||||
with the updated data.
|
||||
|
||||
|
|
@ -136,7 +131,7 @@ form will raise an error.
|
|||
|
||||
import re
|
||||
import copy
|
||||
from src.utils.evtable import Cell, EvTable
|
||||
from src.utils.evtable import EvCell, EvTable
|
||||
from src.utils.utils import all_from_module, to_str, to_unicode
|
||||
from src.utils.ansi import ANSIString
|
||||
|
||||
|
|
@ -160,7 +155,7 @@ class EvForm(object):
|
|||
This object is instantiated with a text file and parses
|
||||
it for rectangular form fields. It can then be fed a
|
||||
mapping so as to populate the fields with fixed-width
|
||||
Cell or Tablets.
|
||||
EvCell or Tablets.
|
||||
|
||||
"""
|
||||
def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs):
|
||||
|
|
@ -176,8 +171,8 @@ class EvForm(object):
|
|||
cells - a dictionary mapping of {id:text}
|
||||
tables - dictionary mapping of {id:EvTable}
|
||||
|
||||
other kwargs are fed as options to the Cells and EvTables
|
||||
(see evtablet.Cell and evtable.EvTable for more info).
|
||||
other kwargs are fed as options to the EvCells and EvTables
|
||||
(see evtablet.EvCell and evtable.EvTable for more info).
|
||||
|
||||
"""
|
||||
self.filename = filename
|
||||
|
|
@ -246,7 +241,7 @@ class EvForm(object):
|
|||
#print "cell_coords:", cell_coords
|
||||
#print "table_coords:", table_coords
|
||||
|
||||
# get rectangles and assign Cells
|
||||
# get rectangles and assign EvCells
|
||||
for key, (iy, leftix, rightix) in cell_coords.items():
|
||||
|
||||
# scan up to find top of rectangle
|
||||
|
|
@ -268,13 +263,13 @@ class EvForm(object):
|
|||
else:
|
||||
break
|
||||
|
||||
# we have our rectangle. Calculate size of Cell.
|
||||
# we have our rectangle. Calculate size of EvCell.
|
||||
iyup = iy - dy_up
|
||||
iydown = iy + dy_down
|
||||
width = rightix - leftix
|
||||
height = abs(iyup - iydown) + 1
|
||||
|
||||
# we have all the coordinates we need. Create Cell.
|
||||
# we have all the coordinates we need. Create EvCell.
|
||||
data = self.cells_mapping.get(key, "")
|
||||
#if key == "1":
|
||||
# print "creating cell '%s' (%s):" % (key, data)
|
||||
|
|
@ -285,7 +280,7 @@ class EvForm(object):
|
|||
#if key=="4":
|
||||
#print "options:", options
|
||||
|
||||
mapping[key] = (iyup, leftix, width, height, Cell(data, width=width, height=height,**options))
|
||||
mapping[key] = (iyup, leftix, width, height, EvCell(data, width=width, height=height,**options))
|
||||
|
||||
# get rectangles and assign Tables
|
||||
for key, (iy, leftix, rightix) in table_coords.items():
|
||||
|
|
@ -355,7 +350,7 @@ class EvForm(object):
|
|||
tables - a dictionary of {identifier:table}
|
||||
|
||||
kwargs will be forwarded to tables/cells. See
|
||||
evtable.Cell and evtable.EvTable for info.
|
||||
evtable.EvCell and evtable.EvTable for info.
|
||||
|
||||
"""
|
||||
# clean kwargs (these cannot be overridden)
|
||||
|
|
@ -441,3 +436,4 @@ def _test():
|
|||
|
||||
# unicode is required since the example contains non-ascii characters
|
||||
print unicode(form)
|
||||
return form
|
||||
|
|
|
|||
|
|
@ -30,15 +30,17 @@ Result:
|
|||
| This is a single row | | | |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
|
||||
As seen, the table will automatically expand with empty cells to
|
||||
make the table symmetric.
|
||||
As seen, the table will automatically expand with empty cells to make
|
||||
the table symmetric.
|
||||
|
||||
Tables can be restricted to a given width.
|
||||
|
||||
table.reformat(width=50, align="l")
|
||||
|
||||
(We could just have added these keywords to the table
|
||||
creation call) yields the following result:
|
||||
(We could just have added these keywords to the table creation call)
|
||||
|
||||
This yields the following result:
|
||||
|
||||
+-----------+------------+-----------+-----------+
|
||||
| Heading1 | Heading2 | | |
|
||||
+~~~~~~~~~~~+~~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~+
|
||||
|
|
@ -57,23 +59,45 @@ creation call) yields the following result:
|
|||
| row | | | |
|
||||
+-----------+------------+-----------+-----------+
|
||||
|
||||
When adding new rows/columns their data can have its
|
||||
own alignments (left/center/right, top/center/bottom).
|
||||
Table-columns can be individually formatted. Note that if an
|
||||
individual column is set with a specific width, table auto-balancing
|
||||
will not affect this column (this may lead to the full table being too
|
||||
wide, so be careful mixing fixed-width columns with auto- balancing).
|
||||
Here we change the width and alignment of the column at index 3
|
||||
(Python starts from 0):
|
||||
|
||||
If the height is restricted, cells will be restricted
|
||||
from expanding vertically. This will lead to text
|
||||
contents being cropped. Each cell can only shrink
|
||||
to a minimum width and height of 1.
|
||||
table.reformat_column(3, width=30, align="r")
|
||||
print table
|
||||
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| Heading1 | Headi | | | |
|
||||
| | ng2 | | | |
|
||||
+~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
|
||||
| 1 | 4 | 7 | This is long data | Test1 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| 2 | 5 | 8 | This is even longer data | Test3 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| 3 | 6 | 9 | | Test4 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| This is a | | | | |
|
||||
| single | | | | |
|
||||
| row | | | | |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
|
||||
It is intended to be used with ANSIString for supporting
|
||||
When adding new rows/columns their data can have its own alignments
|
||||
(left/center/right, top/center/bottom).
|
||||
|
||||
If the height is restricted, cells will be restricted from expanding
|
||||
vertically. This will lead to text contents being cropped. Each cell
|
||||
can only shrink to a minimum width and height of 1.
|
||||
|
||||
EvTable is intended to be used with ANSIString for supporting
|
||||
ANSI-coloured string types.
|
||||
|
||||
When a cell is auto-wrapped across multiple lines,
|
||||
ANSI-reset sequences will be put at the end of each
|
||||
wrapped line. This means that the colour of a wrapped
|
||||
cell will not "bleed", but it also means that eventual
|
||||
colour outside
|
||||
When a cell is auto-wrapped across multiple lines, ANSI-reset
|
||||
sequences will be put at the end of each wrapped line. This means that
|
||||
the colour of a wrapped cell will not "bleed", but it also means that
|
||||
eventual colour outside
|
||||
|
||||
"""
|
||||
#from textwrap import wrap
|
||||
|
|
@ -241,9 +265,9 @@ def fill(text, width=70, **kwargs):
|
|||
w = ANSITextWrapper(width=width, **kwargs)
|
||||
return w.fill(text)
|
||||
|
||||
# Cell class (see further down for the EvTable itself)
|
||||
# EvCell class (see further down for the EvTable itself)
|
||||
|
||||
class Cell(object):
|
||||
class EvCell(object):
|
||||
"""
|
||||
Holds a single data cell for the table. A cell has a certain width
|
||||
and height and contains one or more lines of data. It can shrink
|
||||
|
|
@ -287,11 +311,6 @@ class Cell(object):
|
|||
border_top - top border width
|
||||
border_bottom - bottom border width
|
||||
|
||||
crop_string - string to use when cropping sideways,
|
||||
default is '[...]'
|
||||
crop - crop content of cell rather than expand vertically,
|
||||
default=False
|
||||
|
||||
border_char - this will use a single border char for all borders.
|
||||
overruled by individual settings below
|
||||
border_left_char - char used for left border
|
||||
|
|
@ -302,10 +321,16 @@ class Cell(object):
|
|||
corner_char - character used when two borders cross.
|
||||
(default is ""). This is overruled by
|
||||
individual settings below.
|
||||
corner_top_left
|
||||
corner_top_right
|
||||
corner_bottom_left
|
||||
corner_bottom_right
|
||||
corner_top_left_char - char used for "nw" corner
|
||||
corner_top_right_char - char used for "nw" corner
|
||||
corner_bottom_left_char - char used for "sw" corner
|
||||
corner_bottom_right_char - char used for "se" corner
|
||||
|
||||
crop_string - string to use when cropping sideways,
|
||||
default is '[...]'
|
||||
crop - crop content of cell rather than expand vertically,
|
||||
default=False
|
||||
|
||||
|
||||
enforce_size - if true, the width/height of the
|
||||
cell is strictly enforced and
|
||||
|
|
@ -352,11 +377,11 @@ class Cell(object):
|
|||
self.border_top_char = kwargs.get("border_topchar", borderchar if borderchar else "-")
|
||||
self.border_bottom_char = kwargs.get("border_bottom_char", borderchar if borderchar else "-")
|
||||
|
||||
corner = kwargs.get("corner_char", "+")
|
||||
self.corner_top_left = kwargs.get("corner_top_left", corner)
|
||||
self.corner_top_right = kwargs.get("corner_top_right", corner)
|
||||
self.corner_bottom_left = kwargs.get("corner_bottom_left", corner)
|
||||
self.corner_bottom_right = kwargs.get("corner_bottom_right", corner)
|
||||
corner_char = kwargs.get("corner_char", "+")
|
||||
self.corner_top_left_char = kwargs.get("corner_top_left_char", corner_char)
|
||||
self.corner_top_right_char = kwargs.get("corner_top_right_char", corner_char)
|
||||
self.corner_bottom_left_char = kwargs.get("corner_bottom_left_char", corner_char)
|
||||
self.corner_bottom_right_char = kwargs.get("corner_bottom_right_char", corner_char)
|
||||
|
||||
# alignments
|
||||
self.align = kwargs.get("align", "l")
|
||||
|
|
@ -504,14 +529,14 @@ class Cell(object):
|
|||
cwidth = self.width + self.pad_left + self.pad_right + \
|
||||
max(0,self.border_left-1) + max(0, self.border_right-1)
|
||||
|
||||
vfill = self.corner_top_left if left else ""
|
||||
vfill = self.corner_top_left_char if left else ""
|
||||
vfill += cwidth * self.border_top_char
|
||||
vfill += self.corner_top_right if right else ""
|
||||
vfill += self.corner_top_right_char if right else ""
|
||||
top = [vfill for i in range(self.border_top)]
|
||||
|
||||
vfill = self.corner_bottom_left if left else ""
|
||||
vfill = self.corner_bottom_left_char if left else ""
|
||||
vfill += cwidth * self.border_bottom_char
|
||||
vfill += self.corner_bottom_right if right else ""
|
||||
vfill += self.corner_bottom_right_char if right else ""
|
||||
bottom = [vfill for i in range(self.border_bottom)]
|
||||
|
||||
return top + [left + line + right for line in data] + bottom
|
||||
|
|
@ -552,7 +577,7 @@ class Cell(object):
|
|||
|
||||
def reformat(self, **kwargs):
|
||||
"""
|
||||
Reformat the Cell with new options
|
||||
Reformat the EvCell with new options
|
||||
kwargs:
|
||||
as the class __init__
|
||||
"""
|
||||
|
|
@ -590,11 +615,11 @@ class Cell(object):
|
|||
self.border_top_char = kwargs.get("border_topchar", borderchar if borderchar else self.border_top_char)
|
||||
self.border_bottom_char = kwargs.get("border_bottom_char", borderchar if borderchar else self.border_bottom_char)
|
||||
|
||||
corner = kwargs.get("corner_char", None)
|
||||
self.corner_top_left = kwargs.get("corner_top_left", corner if corner is not None else self.corner_top_left)
|
||||
self.corner_top_right = kwargs.get("corner_top_right", corner if corner is not None else self.corner_top_right)
|
||||
self.corner_bottom_left = kwargs.get("corner_bottom_left", corner if corner is not None else self.corner_bottom_left)
|
||||
self.corner_bottom_right = kwargs.get("corner_bottom_right", corner if corner is not None else self.corner_bottom_right)
|
||||
corner_char = kwargs.get("corner_char", None)
|
||||
self.corner_top_left_char = kwargs.get("corner_top_left", corner_char if corner_char is not None else self.corner_top_left_char)
|
||||
self.corner_top_right_char = kwargs.get("corner_top_right", corner_char if corner_char is not None else self.corner_top_right_char)
|
||||
self.corner_bottom_left_char = kwargs.get("corner_bottom_left", corner_char if corner_char is not None else self.corner_bottom_left_char)
|
||||
self.corner_bottom_right_char = kwargs.get("corner_bottom_right", corner_char if corner_char is not None else self.corner_bottom_right_char)
|
||||
|
||||
# fill all other properties
|
||||
for key, value in kwargs.items():
|
||||
|
|
@ -621,6 +646,9 @@ class Cell(object):
|
|||
"""
|
||||
return self.formatted
|
||||
|
||||
def __repr__(self):
|
||||
return ANSIString("EvCel<%s>" % self.formatted)
|
||||
|
||||
def __str__(self):
|
||||
"returns cell contents on string form"
|
||||
return ANSIString("\n").join(self.formatted)
|
||||
|
|
@ -630,14 +658,107 @@ class Cell(object):
|
|||
return unicode(ANSIString("\n").join(self.formatted))
|
||||
|
||||
|
||||
## EvColumn class
|
||||
|
||||
class EvColumn(object):
|
||||
"""
|
||||
Column class
|
||||
|
||||
This class holds a list of Cells to represent a column of a table.
|
||||
It holds operations and settings that affect *all* cells in the
|
||||
column.
|
||||
|
||||
Columns are not intended to be used stand-alone; they should be
|
||||
incorporated into an EvTable (like EvCells)
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
Data for each row in the column
|
||||
Keywords:
|
||||
width - If set, this column will be hardcoded to have
|
||||
this width, regardless of the length of data in
|
||||
each individual cell. The cells will adjust
|
||||
or not depending on other settings. The
|
||||
EvTable will not be allowed to auto-adjust
|
||||
the width of EvColumns with their width set.
|
||||
All EvCell keywords are available, these settings
|
||||
will be applied to every Cell in the column.
|
||||
"""
|
||||
self.width = kwargs.get("width", None)
|
||||
self.options = kwargs
|
||||
self.column = [EvCell(data, **kwargs) for data in args]
|
||||
self._normalize_width()
|
||||
|
||||
def _normalize_width(self):
|
||||
"""
|
||||
Make sure to adjust the width of all cells so we form
|
||||
a coherent and lined-up column.
|
||||
"""
|
||||
col = self.column
|
||||
noptions = copy(self.options)
|
||||
# use fixed width or adjust to the largest cell
|
||||
noptions["width"] = self.width or noptions.get("width") or max(cell.get_width() for cell in col) if col else 0
|
||||
[cell.reformat(**noptions) for cell in col]
|
||||
|
||||
def add_rows(self, *args, **kwargs):
|
||||
"""
|
||||
Add new cells to column. They will be inserted as
|
||||
a series of rows. It will inherit the options
|
||||
of the rest of the column's cells (use update to change
|
||||
options).
|
||||
|
||||
Args:
|
||||
data for the new cells
|
||||
Keywords:
|
||||
ypos - index position in table before which to insert the
|
||||
new column. Uses Python indexing, so to insert at the top,
|
||||
use ypos=0. If not given, data will be inserted at the end
|
||||
of the column.
|
||||
"""
|
||||
ypos = kwargs.get("ypos", None)
|
||||
if ypos is None or ypos > len(self.column):
|
||||
# add to the end
|
||||
self.column.extend([EvCell(data, **self.options) for data in args])
|
||||
else:
|
||||
# insert cells before given index
|
||||
ypos = min(len(self.column)-1, max(0, int(ypos)))
|
||||
new_cells = [EvCell(data, **self.options) for data in args]
|
||||
self.column = self.column[:ypos] + new_cells + self.column[ypos:]
|
||||
self._normalize_width()
|
||||
|
||||
def reformat(self, force_width=False, **kwargs):
|
||||
"""
|
||||
Change the options for the collumn. Will not change width unless
|
||||
the force_width keyword is passed (this is only sent by the
|
||||
EvTable.reformat_column() method)
|
||||
"""
|
||||
self.width = kwargs.get("width", self.width) if force_width else self.width
|
||||
self.options.update(kwargs)
|
||||
self._normalize_width()
|
||||
|
||||
def __repr__(self):
|
||||
return "EvColumn<%i cels>" % len(self.column)
|
||||
def __len__(self):
|
||||
return len(self.column)
|
||||
def __iter__(self):
|
||||
return iter(self.column)
|
||||
def __getitem__(self, index):
|
||||
return self.column[index]
|
||||
def __setitem__(self, index, value):
|
||||
self.column[index] = value
|
||||
def __delitem__(self, index):
|
||||
del self.column[index]
|
||||
|
||||
|
||||
## Main Evtable class
|
||||
|
||||
class EvTable(object):
|
||||
"""
|
||||
Table class.
|
||||
|
||||
This table implements an ordered grid of Cells, with
|
||||
all cell boundaries lining up.
|
||||
The table contains of a list of EvColumns, each consisting of EvCells so
|
||||
that the result is a 2D matrix.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -646,7 +767,7 @@ class EvTable(object):
|
|||
headers for the table
|
||||
|
||||
Keywords:
|
||||
table - list of columns (list of lists) for seeding
|
||||
table - list of columns (lists of lists, or lists of EvColumns) for seeding
|
||||
the table. If not given, the table will start
|
||||
out empty
|
||||
header - True/False - turn off header being treated
|
||||
|
|
@ -667,11 +788,11 @@ class EvTable(object):
|
|||
corners. Default is 1.
|
||||
corner_char - character to use in corners when border is
|
||||
active.
|
||||
corner_top_left - character to use in upper left corner of table
|
||||
corner_top_left_char - character to use in upper left corner of table
|
||||
(defaults to corner_char)
|
||||
corner_top_right
|
||||
corner_bottom_left
|
||||
corner_bottom_right
|
||||
corner_top_right_char
|
||||
corner_bottom_left_char
|
||||
corner_bottom_right_char
|
||||
pretty_corners - (default True): use custom characters to make
|
||||
the table corners look "rounded". Uses UTF-8
|
||||
characters.
|
||||
|
|
@ -701,16 +822,16 @@ class EvTable(object):
|
|||
to each cell in the table.
|
||||
|
||||
"""
|
||||
# table itself is a 2D grid - a list of columns
|
||||
# at this point table is a 2D grid - a list of columns
|
||||
# x is the column position, y the row
|
||||
self.table = kwargs.pop("table", [])
|
||||
table = kwargs.pop("table", [])
|
||||
|
||||
# header is a list of texts. We merge it to the table's top
|
||||
header = list(args)
|
||||
self.header = header != []
|
||||
if self.header:
|
||||
if self.table:
|
||||
excess = len(header) - len(self.table)
|
||||
if table:
|
||||
excess = len(header) - len(table)
|
||||
if excess > 0:
|
||||
# header bigger than table
|
||||
self.table.extend([] for i in range(excess))
|
||||
|
|
@ -718,9 +839,9 @@ class EvTable(object):
|
|||
# too short header
|
||||
header.extend(_to_ansi(["" for i in range(abs(excess))]))
|
||||
for ix, heading in enumerate(header):
|
||||
self.table[ix].insert(0, heading)
|
||||
table[ix].insert(0, heading)
|
||||
else:
|
||||
self.table = [[heading] for heading in header]
|
||||
table = [[heading] for heading in header]
|
||||
# even though we inserted the header, we can still turn off
|
||||
# header border underling etc. We only allow this if a header
|
||||
# was actually set
|
||||
|
|
@ -740,10 +861,10 @@ class EvTable(object):
|
|||
self.border_width = kwargs.get("border_width", 1)
|
||||
self.corner_char = kwargs.get("corner_char", "+")
|
||||
pcorners = kwargs.pop("pretty_corners", False)
|
||||
self.corner_top_left = _to_ansi(kwargs.pop("corner_top_left", '.' if pcorners else self.corner_char))
|
||||
self.corner_top_right = _to_ansi(kwargs.pop("corner_top_right", '.' if pcorners else self.corner_char))
|
||||
self.corner_bottom_left = _to_ansi(kwargs.pop("corner_bottom_left", ' ' if pcorners else self.corner_char))
|
||||
self.corner_bottom_right = _to_ansi(kwargs.pop("corner_bottom_right", ' ' if pcorners else self.corner_char))
|
||||
self.corner_top_left_char = _to_ansi(kwargs.pop("corner_top_left_char", '.' if pcorners else self.corner_char))
|
||||
self.corner_top_right_char = _to_ansi(kwargs.pop("corner_top_right_char", '.' if pcorners else self.corner_char))
|
||||
self.corner_bottom_left_char = _to_ansi(kwargs.pop("corner_bottom_left_char", ' ' if pcorners else self.corner_char))
|
||||
self.corner_bottom_right_char = _to_ansi(kwargs.pop("corner_bottom_right_char", ' ' if pcorners else self.corner_char))
|
||||
|
||||
self.width = kwargs.pop("width", None)
|
||||
self.height = kwargs.pop("height", None)
|
||||
|
|
@ -760,9 +881,9 @@ class EvTable(object):
|
|||
# save options
|
||||
self.options = kwargs
|
||||
|
||||
if self.table:
|
||||
# generate the table on the fly
|
||||
self.table = [[Cell(data, **kwargs) for data in col] for col in self.table]
|
||||
# use the temporary table to generate the table on the fly, as a list of EvColumns.
|
||||
# If the input is not iterable we assume it is an EvColumn.
|
||||
self.table = [col if isinstance(col, EvColumn) else EvColumn(*col, **kwargs) for col in table]
|
||||
|
||||
# this is the actual working table
|
||||
self.worktable = None
|
||||
|
|
@ -784,13 +905,13 @@ class EvTable(object):
|
|||
def corners(ret):
|
||||
"Handle corners of table"
|
||||
if ix == 0 and iy == 0:
|
||||
ret["corner_top_left"] = self.corner_top_left
|
||||
ret["corner_top_left_char"] = self.corner_top_left_char
|
||||
if ix == nx and iy == 0:
|
||||
ret["corner_top_right"] = self.corner_top_right
|
||||
ret["corner_top_right_char"] = self.corner_top_right_char
|
||||
if ix == 0 and iy == ny:
|
||||
ret["corner_bottom_left"] = self.corner_bottom_left
|
||||
ret["corner_bottom_left_char"] = self.corner_bottom_left_char
|
||||
if ix == nx and iy == ny:
|
||||
ret["corner_bottom_right"] = self.corner_bottom_right
|
||||
ret["corner_bottom_right_char"] = self.corner_bottom_right_char
|
||||
return ret
|
||||
|
||||
def left_edge(ret):
|
||||
|
|
@ -885,15 +1006,15 @@ class EvTable(object):
|
|||
self.worktable = deepcopy(self.table)
|
||||
options = copy(self.options)
|
||||
|
||||
# balance number of rows
|
||||
# balance number of rows to make a rectangular table
|
||||
ncols = len(self.worktable)
|
||||
nrows = [len(col) for col in self.worktable]
|
||||
nrowmax = max(nrows) if nrows else 0
|
||||
for icol, nrow in enumerate(nrows):
|
||||
if nrow < nrowmax:
|
||||
# add more rows
|
||||
self.worktable[icol].extend([Cell("", **self.options) for i in range(nrowmax-nrow)])
|
||||
|
||||
# add more rows to too-short columns
|
||||
empty_rows = ["" for i in range(nrowmax-nrow)]
|
||||
self.worktable[icol].add_rows(*empty_rows)
|
||||
self.ncols = ncols
|
||||
self.nrows = nrowmax
|
||||
|
||||
|
|
@ -938,12 +1059,11 @@ class EvTable(object):
|
|||
|
||||
# reformat worktable (for width align)
|
||||
for ix, col in enumerate(self.worktable):
|
||||
for iy, cell in enumerate(col):
|
||||
try:
|
||||
cell.reformat(width=cwidths[ix], **options)
|
||||
except Exception, e:
|
||||
msg = "ix=%s, iy=%s, width=%s: %s" % (ix, iy, cwidths[ix], e.message)
|
||||
raise Exception ("Error in horizontal allign:\n %s" % msg)
|
||||
try:
|
||||
col.reformat(width=cwidths[ix], **options)
|
||||
except Exception, e:
|
||||
msg = "ix=%s, width=%s: %s" % (ix, cwidths[ix], e.message)
|
||||
raise #Exception ("Error in horizontal allign:\n %s" % msg)
|
||||
|
||||
# equalize heights for each row (we must do this here, since it may have changed to fit new widths)
|
||||
cheights = [max(cell.get_height() for cell in (col[iy] for col in self.worktable)) for iy in range(nrowmax)]
|
||||
|
|
@ -1031,6 +1151,9 @@ class EvTable(object):
|
|||
empty rows in the other columns. If too few,
|
||||
the new column with get new empty rows. All
|
||||
filling rows are added to the end.
|
||||
Args:
|
||||
Either a single EvColumn instance or
|
||||
a number of data to be used to create a new column
|
||||
keyword-
|
||||
header - the header text for the column
|
||||
xpos - index position in table before which
|
||||
|
|
@ -1043,25 +1166,30 @@ class EvTable(object):
|
|||
options = dict(self.options.items() + kwargs.items())
|
||||
|
||||
xpos = kwargs.get("xpos", None)
|
||||
column = [Cell(data, **options) for data in args]
|
||||
if args and isinstance(args[0], EvColumn):
|
||||
column = args[0]
|
||||
else:
|
||||
column = EvColumn(*args, **options)
|
||||
htable = self.nrows
|
||||
excess = self.ncols - htable
|
||||
|
||||
if excess > 0:
|
||||
# we need to add new rows to table
|
||||
for col in self.table:
|
||||
col.extend([Cell("", **options) for i in range(excess)])
|
||||
empty_rows = ["" for i in range(excess)]
|
||||
col.add_rows(*empty_rows, **options)
|
||||
elif excess < 0:
|
||||
# we need to add new rows to new column
|
||||
column.extend([Cell("", **options) for i in range(abs(excess))])
|
||||
empty_rows = ["" for i in range(abs(excess))]
|
||||
column.add_rows(*empty_rows, **options)
|
||||
|
||||
header = kwargs.get("header", None)
|
||||
if header:
|
||||
column.insert(0, Cell(unicode(header), **options))
|
||||
column.add_rows(unicode(header), ypos=0, **options)
|
||||
self.header = True
|
||||
elif self.header:
|
||||
# we have a header already. Offset
|
||||
column.insert(0, Cell("", **options))
|
||||
column.add_rows("", ypos=0, **options)
|
||||
if xpos is None or xpos > len(self.table) - 1:
|
||||
# add to the end
|
||||
self.table.append(column)
|
||||
|
|
@ -1085,32 +1213,33 @@ class EvTable(object):
|
|||
input new row. If not given, will be added
|
||||
to the end. Uses Python indexing (so first row is
|
||||
ypos=0)
|
||||
See Cell class for other keyword arguments
|
||||
See EvCell class for other keyword arguments
|
||||
"""
|
||||
# this will replace default options with new ones without changing default
|
||||
row = list(args)
|
||||
options = dict(self.options.items() + kwargs.items())
|
||||
|
||||
ypos = kwargs.get("ypos", None)
|
||||
row = [Cell(data, **options) for data in args]
|
||||
htable = len(self.table[0]) if len(self.table)>0 else 0 # assuming balanced table
|
||||
excess = len(row) - len(self.table)
|
||||
|
||||
if excess > 0:
|
||||
# we need to add new empty columns to table
|
||||
self.table.extend([[Cell("", **options) for i in range(htable)] for k in range(excess)])
|
||||
empty_rows = ["" for i in range(htable)]
|
||||
self.table.extend([EvColumn(*empty_rows, **options) for i in range(excess)])
|
||||
elif excess < 0:
|
||||
# we need to add more cells to row
|
||||
row.extend([Cell("", **options) for i in range(abs(excess))])
|
||||
row.extend(["" for i in range(abs(excess))])
|
||||
|
||||
if ypos is None or ypos > htable - 1:
|
||||
# add new row to the end
|
||||
for icol, col in enumerate(self.table):
|
||||
col.append(row[icol])
|
||||
col.add_rows(row[icol], **options)
|
||||
else:
|
||||
# insert row elsewhere
|
||||
ypos = min(htable-1, max(0, int(ypos)))
|
||||
for icol, col in enumerate(self.table):
|
||||
col.insert(ypos, row[icol])
|
||||
col.add_rows(row[icol], ypos=ypos, **options)
|
||||
self._balance()
|
||||
|
||||
def reformat(self, **kwargs):
|
||||
|
|
@ -1124,20 +1253,30 @@ class EvTable(object):
|
|||
|
||||
hchar = kwargs.pop("header_line_char", self.header_line_char)
|
||||
|
||||
# border settings are also passed on into Cells (so kwargs.get, not kwargs.pop)
|
||||
# border settings are also passed on into EvCells (so kwargs.get, not kwargs.pop)
|
||||
self.header_line_char = hchar[0] if hchar else self.header_line_char
|
||||
self.border_width = kwargs.get("border_width", self.border_width)
|
||||
self.corner_char = kwargs.get("corner_char", self.corner_char)
|
||||
self.header_line_char = kwargs.get("header_line_char", self.header_line_char)
|
||||
|
||||
self.corner_top_left = _to_ansi(kwargs.pop("corner_top_left", self.corner_char))
|
||||
self.corner_top_right = _to_ansi(kwargs.pop("corner_top_right", self.corner_char))
|
||||
self.corner_bottom_left = _to_ansi(kwargs.pop("corner_bottom_left", self.corner_char))
|
||||
self.corner_bottom_right = _to_ansi(kwargs.pop("corner_bottom_right", self.corner_char))
|
||||
self.corner_top_left_char = _to_ansi(kwargs.pop("corner_top_left_char", self.corner_char))
|
||||
self.corner_top_right_char = _to_ansi(kwargs.pop("corner_top_right_char", self.corner_char))
|
||||
self.corner_bottom_left_char = _to_ansi(kwargs.pop("corner_bottom_left_char", self.corner_char))
|
||||
self.corner_bottom_right_char = _to_ansi(kwargs.pop("corner_bottom_right_char", self.corner_char))
|
||||
|
||||
self.options.update(kwargs)
|
||||
self._balance()
|
||||
|
||||
def reformat_column(self, index, **kwargs):
|
||||
"""
|
||||
Sends custom options to a specific column in the table. The column
|
||||
is identified by its index in the table (0-Ncol)
|
||||
"""
|
||||
if index > len(self.table):
|
||||
raise Exception("Not a valid column index")
|
||||
self.table[index].reformat(force_width=True, **kwargs)
|
||||
self._balance()
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
Return lines of table as a list
|
||||
|
|
@ -1156,9 +1295,12 @@ def _test():
|
|||
table = EvTable("{yHeading1{n", "{gHeading2{n", table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
|
||||
table.add_column("{rThis is long data{n", "{bThis is even longer data{n")
|
||||
table.add_row("This is a single row")
|
||||
col = EvColumn("Test1", "Test3", "Test4", width=10)
|
||||
table.add_column(col)
|
||||
print unicode(table)
|
||||
table.reformat(width=50)
|
||||
print unicode(table)
|
||||
return table
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue