6 class Table(container
.Container
):
7 """A table style container.
9 <p>If you know HTML, this should all work roughly how you would expect. If you are not
10 familiar with HTML, please read <a href="http://www.w3.org/TR/REC-html40/struct/tables.html">Tables in HTML Documents</a>. Pay attention to TABLE, TR, TD related parts of the document.</p>
14 <strong>Example</strong>
19 t.td(gui.Label("First Name"), align=-1)
23 t.td(gui.Label("Last Name"), align=-1)
30 def __init__(self
, **params
):
31 params
.setdefault('cls','table')
32 container
.Container
.__init
__(self
, **params
)
38 return len(self
._rows
)
42 return len(self
._rows
[0])
46 def remove_row(self
, n
): #NOTE: won't work in all cases.
47 if n
>= self
.getRows():
48 print "Trying to remove a nonexistant row:", n
, "there are only", self
.getRows(), "rows"
51 for cell
in self
._rows
[n
]:
52 if isinstance(cell
, dict) and cell
["widget"] in self
.widgets
:
53 #print 'removing widget'
54 self
.widgets
.remove(cell
["widget"])
58 for w
in self
.widgets
:
59 if w
.style
.row
> n
: w
.style
.row
-= 1
64 #self.rect.w, self.rect.h = self.resize()
78 #print 'clear',self,self._rows
81 self
._rows
.append([None for x
in xrange(self
.getColumns())])
84 """Start on the next row."""
89 if self
.getRows() <= self
._curRow
:
95 for row
in self
._rows
:
98 def _setCell(self
, w
, col
, row
, colspan
=1, rowspan
=1):
99 #make room for the widget by adding columns and rows
100 while self
.getColumns() < col
+ colspan
:
102 while self
.getRows() < row
+ rowspan
:
105 #print w.__class__.__name__,col,row,colspan,rowspan
107 #actual widget setting and modification stuff
109 w
.style
.row
= row
#HACK - to work with gal's list
110 w
.style
.col
= col
#HACK - to work with gal's list
111 self
._rows
[row
][col
] = {"widget":w
, "colspan":colspan
, "rowspan":rowspan
}
112 self
.widgets
.append(self
._rows
[row
][col
]["widget"])
114 #set the spanned columns
115 #for acell in xrange(col + 1, col + colspan):
116 # self._rows[row][acell] = True
118 #set the spanned rows and the columns on them
119 #for arow in xrange(row + 1, row + rowspan):
120 # for acell in xrange(col, col + colspan): #incorrect?
121 # self._rows[arow][acell] = True
123 for arow
in xrange(row
, row
+ rowspan
):
124 for acell
in xrange(col
, col
+ colspan
): #incorrect?
125 if row
!= arow
or col
!= acell
:
126 self
._rows
[arow
][acell
] = True
129 def td(self
, w
, col
=None, row
=None, colspan
=1, rowspan
=1, **params
):
130 """Add a widget to a table after wrapping it in a TD container.
132 <pre>Table.td(w,col=None,row=None,colspan=1,rowspan=1,**params)</pre>
138 <dt>colspan<dd>colspan
139 <dt>rowspan<dd>rowspan
140 <dt>align<dd>horizontal alignment (-1,0,1)
141 <dt>valign<dd>vertical alignment (-1,0,1)
142 <dt>params<dd>other params for the TD container, style information, etc
146 Table
.add(self
,_Table_td(w
, **params
), col
=col
, row
=row
, colspan
=colspan
, rowspan
=rowspan
)
148 def add(self
, w
, col
=None, row
=None, colspan
=1, rowspan
=1):
149 """Add a widget directly into the table, without wrapping it in a TD container.
151 <pre>Table.add(w,col=None,row=None,colspan=1,rowspan=1)</pre>
153 <p>See Table.td for an explanation of the parameters.</p>
156 #if no row was specifically specified, set it to the current row
161 #if its going to be a new row, have it be on the first column
162 if row
>= self
.getRows():
165 #try to find an open cell for the widget
167 for cell
in xrange(self
.getColumns()):
168 if col
is None and not self
._rows
[row
][cell
]:
172 #otherwise put the widget in a new column
174 col
= self
.getColumns()
176 self
._setCell
(w
, col
, row
, colspan
=colspan
, rowspan
=rowspan
)
182 if hasattr(w
,'_table_td'): w
= w
._table
_td
183 row
,col
= w
.style
.row
,w
.style
.col
184 cell
= self
._rows
[row
][col
]
185 colspan
,rowspan
= cell
['colspan'],cell
['rowspan']
187 for arow
in xrange(row
, row
+ rowspan
):
188 for acell
in xrange(col
, col
+ colspan
): #incorrect?
189 self
._rows
[arow
][acell
] = False
190 self
.widgets
.remove(w
)
195 def resize(self
, width
=None, height
=None):
196 #if 1 or self.getRows() == 82:
198 #print 'resize',self.getRows(),self.getColumns(),width,height
200 #for obj,fname,line,fnc,code,n in inspect.stack()[9:20]:
201 # print fname,line,':',fnc,code[0].strip()
204 #resize the widgets to their smallest size
205 for w
in self
.widgets
:
206 w
.rect
.w
, w
.rect
.h
= w
.resize()
208 #calculate row heights and column widths
209 rowsizes
= [0 for y
in xrange(self
.getRows())]
210 columnsizes
= [0 for x
in xrange(self
.getColumns())]
211 for row
in xrange(self
.getRows()):
212 for cell
in xrange(self
.getColumns()):
213 if self
._rows
[row
][cell
] and self
._rows
[row
][cell
] is not True:
214 if not self
._rows
[row
][cell
]["colspan"] > 1:
215 columnsizes
[cell
] = max(columnsizes
[cell
], self
._rows
[row
][cell
]["widget"].rect
.w
)
216 if not self
._rows
[row
][cell
]["rowspan"] > 1:
217 rowsizes
[row
] = max(rowsizes
[row
], self
._rows
[row
][cell
]["widget"].rect
.h
)
219 #distribute extra space if necessary for wide colspanning/rowspanning
220 for row
in xrange(self
.getRows()):
221 for cell
in xrange(self
.getColumns()):
222 if self
._rows
[row
][cell
] and self
._rows
[row
][cell
] is not True:
223 if self
._rows
[row
][cell
]["colspan"] > 1:
224 columns
= xrange(cell
, cell
+ self
._rows
[row
][cell
]["colspan"])
227 totalwidth
+= columnsizes
[acol
]
228 if totalwidth
< self
._rows
[row
][cell
]["widget"].rect
.w
:
230 columnsizes
[acol
] += _table_div(self
._rows
[row
][cell
]["widget"].rect
.w
- totalwidth
, self
._rows
[row
][cell
]["colspan"],acol
)
231 if self
._rows
[row
][cell
]["rowspan"] > 1:
232 rows
= xrange(row
, row
+ self
._rows
[row
][cell
]["rowspan"])
235 totalheight
+= rowsizes
[arow
]
236 if totalheight
< self
._rows
[row
][cell
]["widget"].rect
.h
:
238 rowsizes
[arow
] += _table_div(self
._rows
[row
][cell
]["widget"].rect
.h
- totalheight
, self
._rows
[row
][cell
]["rowspan"],arow
)
240 #make everything fill out to self.style.width, self.style.heigh, not exact, but pretty close...
241 w
, h
= sum(columnsizes
), sum(rowsizes
)
242 if w
> 0 and w
< self
.style
.width
and len(columnsizes
):
243 d
= (self
.style
.width
- w
)
244 for n
in xrange(0, len(columnsizes
)):
246 columnsizes
[n
] += v
* d
/ w
247 if h
> 0 and h
< self
.style
.height
and len(rowsizes
):
248 d
= (self
.style
.height
- h
) / len(rowsizes
)
249 for n
in xrange(0, len(rowsizes
)):
251 rowsizes
[n
] += v
* d
/ h
253 #set the widget's position by calculating their row/column x/y offset
254 cellpositions
= [[[sum(columnsizes
[0:cell
]), sum(rowsizes
[0:row
])] for cell
in xrange(self
.getColumns())] for row
in xrange(self
.getRows())]
255 for row
in xrange(self
.getRows()):
256 for cell
in xrange(self
.getColumns()):
257 if self
._rows
[row
][cell
] and self
._rows
[row
][cell
] is not True:
258 x
, y
= cellpositions
[row
][cell
]
259 w
= sum(columnsizes
[cell
:cell
+self
._rows
[row
][cell
]["colspan"]])
260 h
= sum(rowsizes
[row
:row
+self
._rows
[row
][cell
]["rowspan"]])
262 widget
= self
._rows
[row
][cell
]["widget"]
265 if 1 and (w
,h
) != (widget
.rect
.w
,widget
.rect
.h
):
267 # print widget.widget.__class__.__name__, (widget.rect.w,widget.rect.h),'=>',(w,h)
268 widget
.rect
.w
, widget
.rect
.h
= widget
.resize(w
, h
)
270 #print self._rows[row][cell]["widget"].rect
273 #print sum(columnsizes)
274 #size = sum(columnsizes), sum(rowsizes); print size
276 #return the tables final size
277 return sum(columnsizes
),sum(rowsizes
)
280 def _table_div(a
,b
,c
):
282 if r
!= 0 and (c
%b
)<r
: v
+= 1
285 class _Table_td(container
.Container
):
286 def __init__(self
,widget
,**params
):#hexpand=0,vexpand=0,
287 container
.Container
.__init
__(self
,**params
)
289 #self.hexpand=hexpand
290 #self.vexpand=vexpand
291 widget
._table
_td
= self
294 def resize(self
,width
=None,height
=None):
297 #expansion code, but i didn't like the idea that much..
298 #a bit obscure, fairly useless when a user can just
299 #add a widget to a table instead of td it in.
301 #if self.hexpand: ww = self.style.width
302 #if self.vexpand: hh = self.style.height
303 #if self.hexpand and width != None: ww = max(ww,width)
304 #if self.vexpand and height != None: hh = max(hh,height)
305 #w.rect.w,w.rect.h = w.resize(ww,hh)
307 #why bother, just do the lower mentioned item...
308 w
.rect
.w
,w
.rect
.h
= w
.resize()
310 #this should not be needed, widgets should obey their sizing on their own.
312 # if (self.style.width!=0 and w.rect.w > self.style.width) or (self.style.height!=0 and w.rect.h > self.style.height):
314 # if self.style.width: ww = self.style.width
315 # if self.style.height: hh = self.style.height
316 # w.rect.w,w.rect.h = w.resize(ww,hh)
319 #in the case that the widget is too big, we try to resize it
320 if (width
!= None and width
< w
.rect
.w
) or (height
!= None and height
< w
.rect
.h
):
321 w
.rect
.w
,w
.rect
.h
= w
.resize(width
,height
)
323 width
= max(width
,w
.rect
.w
,self
.style
.width
) #,self.style.cell_width)
324 height
= max(height
,w
.rect
.h
,self
.style
.height
) #,self.style.cell_height)
328 w
.rect
.x
= (self
.style
.align
+1)*dx
/2
329 w
.rect
.y
= (self
.style
.valign
+1)*dy
/2