Here's one way to do it in a very flexible manner:
# a simple function to do our line-splitting per value
def split_value(value, width):
result = []
while len(value) > width: # while our string is longer than allowed
split_index = value.rfind(" ", 0, width)
if split_index == -1: # no space in our current chunk, we must do hard-break
split_index = width - 1 # set the split to our column width point
result.append(value[:split_index + 1]) # add the current slice as a sub-row
value = value[split_index + 1:] # remove the added slice from our data
if value: # there are leftovers from slicing, add them as the last piece
result.append(value)
return result
# and our main function...
def draw_table(data, columns, table_width, column_border=1):
column_data = [data[i::columns] for i in range(columns)] # split the data into columns
column_width = table_width // columns - column_border # max characters per column
column_template = ("{} " * (columns - 1)) + "{}" # a simple template for our columns
empty_value = " " * (column_width + column_border) # what to print when there's no value
rows = len(max(column_data, key=len)) # in case we have more data in some of the columns
for row in range(rows): # lets print our rows
row_data = [split_value(x[row], column_width) if len(x) > row else []
for x in column_data] # lets populate our row
subrows = len(max(row_data, key=len)) # number of subrows for the current row
for subrow in range(subrows): # lets go through each of them and print them out
print(column_template.format(*[x[subrow].ljust(column_width+column_border)
if len(x) > subrow else empty_value
for x in row_data])) # print our (split) row
It's a bit twisted but gets the job done reliably and it's not all that hard to follow if you read the comments. It should produce exactly what you asked for (tho your desired result doesn't seem to fit the data you have in your list):
listObj = ['Pre-Condition:', 'Condition:', 'Output:',
'Button is OFF', '-', 'Speed is not on',
'Button Enabled is OFF', 'Enabled is ON',
'Speed is on', 'Button Active is ON', 'Active is OFF',
'Hold steady true north', 'Button States is HOLD',
'Button States is ACCELERATOR OVERRIDE AND Set stuff is on <Stuff here>',
'Pedal to the medal here guys']
# table with three columns, two spaces between columns and of total width of 80 characters
draw_table(listObj, 3, 80, 2)
Produces:
Pre-Condition: Condition: Output:
Button is OFF - Speed is not on
Button Enabled is OFF Enabled is ON Speed is on
Button Active is ON Active is OFF Hold steady true north
Button States is HOLD Button States is Pedal to the medal here
ACCELERATOR OVERRIDE guys
AND Set stuff is on
<Stuff here>
As a bonus, it supports uneven lists so you can do something like:
listObj = ['Pre-Condition:', 'Condition:', 'Output:',
'Button is OFF', '-', 'Speed is not on',
'Button Enabled is OFF', 'Enabled is ON',
'Speed is on', 'Button Active is ON', 'Active is OFF',
'Hold steady true north', 'Button States is HOLD',
'Button States is ACCELERATOR OVERRIDE AND Set stuff is on...',
'Pedal to the medal here guys', "One extra value to prove the flow"]
draw_table(listObj, 3, 80, 2)
Which will produce:
Pre-Condition: Condition: Output:
Button is OFF - Speed is not on
Button Enabled is OFF Enabled is ON Speed is on
Button Active is ON Active is OFF Hold steady true north
Button States is HOLD Button States is Pedal to the medal here
ACCELERATOR OVERRIDE guys
AND Set stuff is on...
One extra value to
prove the flow
Future upgrades like variable column widths shouldn't be that difficult as the row data splits are external so any size can be added.