Make EvTable respect col-widths while retaining total table width.
Resolves #1614.
This commit is contained in:
parent
060cfde23e
commit
9bbfc422ee
3 changed files with 79 additions and 21 deletions
|
|
@ -253,7 +253,7 @@ class CmdMail(default_cmds.MuxCommand):
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
table.reformat_column(0, width=6)
|
table.reformat_column(0, width=6)
|
||||||
table.reformat_column(1, width=17)
|
table.reformat_column(1, width=18)
|
||||||
table.reformat_column(2, width=34)
|
table.reformat_column(2, width=34)
|
||||||
table.reformat_column(3, width=13)
|
table.reformat_column(3, width=13)
|
||||||
table.reformat_column(4, width=7)
|
table.reformat_column(4, width=7)
|
||||||
|
|
|
||||||
|
|
@ -893,6 +893,9 @@ class EvColumn(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
col = self.column
|
col = self.column
|
||||||
|
# fixed options for the column will override those requested in the call!
|
||||||
|
# this is particularly relevant to things like width/height, to avoid
|
||||||
|
# fixed-widths columns from being auto-balanced
|
||||||
kwargs.update(self.options)
|
kwargs.update(self.options)
|
||||||
# use fixed width or adjust to the largest cell
|
# use fixed width or adjust to the largest cell
|
||||||
if "width" not in kwargs:
|
if "width" not in kwargs:
|
||||||
|
|
@ -1283,24 +1286,58 @@ class EvTable(object):
|
||||||
cwidths_min = [max(cell.get_min_width() for cell in col) for col in self.worktable]
|
cwidths_min = [max(cell.get_min_width() for cell in col) for col in self.worktable]
|
||||||
cwmin = sum(cwidths_min)
|
cwmin = sum(cwidths_min)
|
||||||
|
|
||||||
if cwmin > width:
|
# get which cols have separately set widths - these should be locked
|
||||||
# we cannot shrink any more
|
# note that we need to remove cwidths_min for each lock to avoid counting
|
||||||
raise Exception("Cannot shrink table width to %s. Minimum size is %s." % (self.width, cwmin))
|
# it twice (in cwmin and in locked_cols)
|
||||||
|
locked_cols = {icol: col.options['width'] - cwidths_min[icol]
|
||||||
|
for icol, col in enumerate(self.worktable) if 'width' in col.options}
|
||||||
|
locked_width = sum(locked_cols.values())
|
||||||
|
|
||||||
|
excess = width - cwmin - locked_width
|
||||||
|
|
||||||
|
if len(locked_cols) >= ncols and excess:
|
||||||
|
# we can't adjust the width at all - all columns are locked
|
||||||
|
raise Exception("Cannot balance table to width %s - "
|
||||||
|
"all columns have a set, fixed width summing to %s!" % (
|
||||||
|
self.width, sum(cwidths)))
|
||||||
|
|
||||||
|
if excess < 0:
|
||||||
|
# the locked cols makes it impossible
|
||||||
|
raise Exception("Cannot shrink table width to %s. "
|
||||||
|
"Minimum size (and/or fixed-width columns) "
|
||||||
|
"sets minimum at %s." % (self.width, cwmin + locked_width))
|
||||||
|
|
||||||
excess = width - cwmin
|
|
||||||
if self.evenwidth:
|
if self.evenwidth:
|
||||||
# make each column of equal width
|
# make each column of equal width
|
||||||
for _ in range(excess):
|
# use cwidths as a work-array to track weights
|
||||||
|
cwidths = copy(cwidths_min)
|
||||||
|
correction = 0
|
||||||
|
while correction < excess:
|
||||||
# flood-fill the minimum table starting with the smallest columns
|
# flood-fill the minimum table starting with the smallest columns
|
||||||
ci = cwidths_min.index(min(cwidths_min))
|
ci = cwidths.index(min(cwidths))
|
||||||
|
if ci in locked_cols:
|
||||||
|
# locked column, make sure it's not picked again
|
||||||
|
cwidths[ci] += 9999
|
||||||
|
cwidths_min[ci] = locked_cols[ci]
|
||||||
|
else:
|
||||||
cwidths_min[ci] += 1
|
cwidths_min[ci] += 1
|
||||||
|
correction += 1
|
||||||
cwidths = cwidths_min
|
cwidths = cwidths_min
|
||||||
else:
|
else:
|
||||||
# make each column expand more proportional to their data size
|
# make each column expand more proportional to their data size
|
||||||
for _ in range(excess):
|
# we use cwidth as a work-array to track weights
|
||||||
|
correction = 0
|
||||||
|
while correction < excess:
|
||||||
# fill wider columns first
|
# fill wider columns first
|
||||||
ci = cwidths.index(max(cwidths))
|
ci = cwidths.index(max(cwidths))
|
||||||
|
if ci in locked_cols:
|
||||||
|
# locked column, make sure it's not picked again
|
||||||
|
cwidths[ci] -= 9999
|
||||||
|
cwidths_min[ci] = locked_cols[ci]
|
||||||
|
else:
|
||||||
cwidths_min[ci] += 1
|
cwidths_min[ci] += 1
|
||||||
|
correction += 1
|
||||||
|
# give a just changed col less prio next run
|
||||||
cwidths[ci] -= 3
|
cwidths[ci] -= 3
|
||||||
cwidths = cwidths_min
|
cwidths = cwidths_min
|
||||||
|
|
||||||
|
|
@ -1323,28 +1360,46 @@ class EvTable(object):
|
||||||
for cell in (col[iy] for col in self.worktable)) for iy in range(nrowmax)]
|
for cell in (col[iy] for col in self.worktable)) for iy in range(nrowmax)]
|
||||||
chmin = sum(cheights_min)
|
chmin = sum(cheights_min)
|
||||||
|
|
||||||
|
# get which cols have separately set heights - these should be locked
|
||||||
|
# note that we need to remove cheights_min for each lock to avoid counting
|
||||||
|
# it twice (in chmin and in locked_cols)
|
||||||
|
locked_cols = {icol: col.options['height'] - cheights_min[icol]
|
||||||
|
for icol, col in enumerate(self.worktable) if 'height' in col.options}
|
||||||
|
locked_height = sum(locked_cols.values())
|
||||||
|
|
||||||
|
excess = self.height - chmin - locked_height
|
||||||
|
|
||||||
if chmin > self.height:
|
if chmin > self.height:
|
||||||
# we cannot shrink any more
|
# we cannot shrink any more
|
||||||
raise Exception("Cannot shrink table height to %s. Minimum size is %s." % (self.height, chmin))
|
raise Exception("Cannot shrink table height to %s. Minimum "
|
||||||
|
"size (and/or fixed-height rows) sets minimum at %s." % (
|
||||||
|
self.height, chmin + locked_height))
|
||||||
|
|
||||||
# now we add all the extra height up to the desired table-height.
|
# now we add all the extra height up to the desired table-height.
|
||||||
# We do this so that the tallest cells gets expanded first (and
|
# We do this so that the tallest cells gets expanded first (and
|
||||||
# thus avoid getting cropped)
|
# thus avoid getting cropped)
|
||||||
|
|
||||||
excess = self.height - chmin
|
|
||||||
even = self.height % 2 == 0
|
even = self.height % 2 == 0
|
||||||
for position in range(excess):
|
correction = 0
|
||||||
|
while correction < excess:
|
||||||
# expand the cells with the most rows first
|
# expand the cells with the most rows first
|
||||||
if 0 <= position < nrowmax and nrowmax > 1:
|
if 0 <= correction < nrowmax and nrowmax > 1:
|
||||||
# avoid adding to header first round (looks bad on very small tables)
|
# avoid adding to header first round (looks bad on very small tables)
|
||||||
ci = cheights[1:].index(max(cheights[1:])) + 1
|
ci = cheights[1:].index(max(cheights[1:])) + 1
|
||||||
else:
|
else:
|
||||||
ci = cheights.index(max(cheights))
|
ci = cheights.index(max(cheights))
|
||||||
|
if ci in locked_cols:
|
||||||
|
# locked row, make sure it's not picked again
|
||||||
|
cheights[ci] -= 9999
|
||||||
|
cheights_min[ci] = locked_cols[ci]
|
||||||
|
else:
|
||||||
cheights_min[ci] += 1
|
cheights_min[ci] += 1
|
||||||
|
# change balance
|
||||||
if ci == 0 and self.header:
|
if ci == 0 and self.header:
|
||||||
# it doesn't look very good if header expands too fast
|
# it doesn't look very good if header expands too fast
|
||||||
cheights[ci] -= 2 if even else 3
|
cheights[ci] -= 2 if even else 3
|
||||||
cheights[ci] -= 2 if even else 1
|
cheights[ci] -= 2 if even else 1
|
||||||
|
correction += 1
|
||||||
cheights = cheights_min
|
cheights = cheights_min
|
||||||
|
|
||||||
# we must tell cells to crop instead of expanding
|
# we must tell cells to crop instead of expanding
|
||||||
|
|
@ -1554,6 +1609,8 @@ class EvTable(object):
|
||||||
"""
|
"""
|
||||||
if index > len(self.table):
|
if index > len(self.table):
|
||||||
raise Exception("Not a valid column index")
|
raise Exception("Not a valid column index")
|
||||||
|
# we update the columns' options which means eventual width/height
|
||||||
|
# will be 'locked in' and withstand auto-balancing width/height from the table later
|
||||||
self.table[index].options.update(kwargs)
|
self.table[index].options.update(kwargs)
|
||||||
self.table[index].reformat(**kwargs)
|
self.table[index].reformat(**kwargs)
|
||||||
|
|
||||||
|
|
@ -1569,6 +1626,7 @@ class EvTable(object):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""print table (this also balances it)"""
|
"""print table (this also balances it)"""
|
||||||
|
# h = "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
return str(unicode(ANSIString("\n").join([line for line in self._generate_lines()])))
|
return str(unicode(ANSIString("\n").join([line for line in self._generate_lines()])))
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue