blob: 05a954e5b86f48a4ee8cf8d330715a06b0935204 [file] [log] [blame]
Guido van Rossumc6360141990-10-13 19:23:40 +00001# Module 'tablewin'
2
3# Display a table, with per-item actions:
4
5# A1 | A2 | A3 | .... | AN
6# B1 | B2 | B3 | .... | BN
7# C1 | C2 | C3 | .... | CN
8# .. | .. | .. | .... | ..
9# Z1 | Z2 | Z3 | .... | ZN
10
11# Not all columns need to have the same length.
12# The data structure is a list of columns;
13# each column is a list of items.
14# Each item is a pair of a string and an action procedure.
15# The first item may be a column title.
16
17import stdwin
18import gwin
19
20def open(title, data): # Public function to open a table window
21 #
22 # Set geometry parameters (one day, these may be changeable)
23 #
24 margin = stdwin.textwidth(' ')
25 lineheight = stdwin.lineheight()
26 #
27 # Geometry calculations
28 #
29 colstarts = [0]
30 totwidth = 0
31 maxrows = 0
32 for coldata in data:
33 # Height calculations
34 rows = len(coldata)
35 if rows > maxrows: maxrows = rows
36 # Width calculations
37 width = colwidth(coldata) + margin
38 totwidth = totwidth + width
39 colstarts.append(totwidth)
40 #
41 # Calculate document and window height
42 #
43 docwidth, docheight = totwidth, maxrows*lineheight
44 winwidth, winheight = docwidth, docheight
45 if winwidth > stdwin.textwidth('n')*100: winwidth = 0
46 if winheight > stdwin.lineheight()*30: winheight = 0
47 #
48 # Create the window
49 #
50 stdwin.setdefwinsize(winwidth, winheight)
51 w = gwin.open(title)
52 #
53 # Set properties and override methods
54 #
55 w.data = data
56 w.margin = margin
57 w.lineheight = lineheight
58 w.colstarts = colstarts
59 w.totwidth = totwidth
60 w.maxrows = maxrows
61 w.selection = (-1, -1)
62 w.lastselection = (-1, -1)
63 w.selshown = 0
64 w.setdocsize(docwidth, docheight)
65 w.draw = draw
66 w.mup = mup
67 w.arrow = arrow
68 #
69 # Return
70 #
71 return w
72
73def update(w, data): # Change the data
74 #
75 # Hide selection
76 #
77 hidesel(w, w.begindrawing())
78 #
79 # Get old geometry parameters
80 #
81 margin = w.margin
82 lineheight = w.lineheight
83 #
84 # Geometry calculations
85 #
86 colstarts = [0]
87 totwidth = 0
88 maxrows = 0
89 for coldata in data:
90 # Height calculations
91 rows = len(coldata)
92 if rows > maxrows: maxrows = rows
93 # Width calculations
94 width = colwidth(coldata) + margin
95 totwidth = totwidth + width
96 colstarts.append(totwidth)
97 #
98 # Calculate document and window height
99 #
100 docwidth, docheight = totwidth, maxrows*lineheight
101 #
102 # Set changed properties and change window size
103 #
104 w.data = data
105 w.colstarts = colstarts
106 w.totwidth = totwidth
107 w.maxrows = maxrows
108 w.change((0, 0), (10000, 10000))
109 w.setdocsize(docwidth, docheight)
110 w.change((0, 0), (docwidth, docheight))
111 #
112 # Show selection, or forget it if out of range
113 #
114 showsel(w, w.begindrawing())
115 if not w.selshown: w.selection = (-1, -1)
116
117def colwidth(coldata): # Subroutine to calculate column width
118 maxwidth = 0
119 for string, action in coldata:
120 width = stdwin.textwidth(string)
121 if width > maxwidth: maxwidth = width
122 return maxwidth
123
124def draw(w, ((left, top), (right, bottom))): # Draw method
125 ileft = whichcol(w, left)
126 iright = whichcol(w, right-1) + 1
127 if iright > len(w.data): iright = len(w.data)
128 itop = divmod(top, w.lineheight)[0]
129 if itop < 0: itop = 0
130 ibottom, remainder = divmod(bottom, w.lineheight)
131 if remainder: ibottom = ibottom + 1
132 d = w.begindrawing()
133 if ileft <= w.selection[0] < iright:
134 if itop <= w.selection[1] < ibottom:
135 hidesel(w, d)
136 d.erase((left, top), (right, bottom))
137 for i in range(ileft, iright):
138 col = w.data[i]
139 jbottom = len(col)
140 if ibottom < jbottom: jbottom = ibottom
141 h = w.colstarts[i]
142 v = itop * w.lineheight
143 for j in range(itop, jbottom):
144 string, action = col[j]
145 d.text((h, v), string)
146 v = v + w.lineheight
147 showsel(w, d)
148
149def mup(w, detail): # Mouse up method
150 (h, v), nclicks, button, mask = detail
151 icol = whichcol(w, h)
152 if 0 <= icol < len(w.data):
153 irow = divmod(v, w.lineheight)[0]
154 col = w.data[icol]
155 if 0 <= irow < len(col):
156 string, action = col[irow]
157 action(w, string, (icol, irow), detail)
158
159def whichcol(w, h): # Return column number (may be >= len(w.data))
160 for icol in range(0, len(w.data)):
161 if h < w.colstarts[icol+1]:
162 return icol
163 return len(w.data)
164
165def arrow(w, type):
166 import stdwinsupport
167 S = stdwinsupport
168 if type = S.wc_left:
169 incr = -1, 0
170 elif type = S.wc_up:
171 incr = 0, -1
172 elif type = S.wc_right:
173 incr = 1, 0
174 elif type = S.wc_down:
175 incr = 0, 1
176 else:
177 return
178 icol, irow = w.lastselection
179 icol = icol + incr[0]
180 if icol < 0: icol = len(w.data)-1
181 if icol >= len(w.data): icol = 0
182 if 0 <= icol < len(w.data):
183 irow = irow + incr[1]
184 if irow < 0: irow = len(w.data[icol]) - 1
185 if irow >= len(w.data[icol]): irow = 0
186 else:
187 irow = 0
188 if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
189 w.lastselection = icol, irow
190 string, action = w.data[icol][irow]
191 detail = (0, 0), 1, 1, 1
192 action(w, string, (icol, irow), detail)
193
194
195# Selection management
196# TO DO: allow multiple selected entries
197
198def select(w, selection): # Public function to set the item selection
199 d = w.begindrawing()
200 hidesel(w, d)
201 w.selection = selection
202 showsel(w, d)
203 if w.selshown: lastselection = selection
204
205def hidesel(w, d): # Hide the selection, if shown
206 if w.selshown: invertsel(w, d)
207
208def showsel(w, d): # Show the selection, if hidden
209 if not w.selshown: invertsel(w, d)
210
211def invertsel(w, d): # Invert the selection, if valid
212 icol, irow = w.selection
213 if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
214 left = w.colstarts[icol]
215 right = w.colstarts[icol+1]
216 top = irow * w.lineheight
217 bottom = (irow+1) * w.lineheight
218 d.invert((left, top), (right, bottom))
219 w.selshown = (not w.selshown)
220
221
222# Demonstration
223
224def demo_action(w, string, (icol, irow), detail): # Action function for demo
225 select(w, (irow, icol))
226
227def demo(): # Demonstration
228 da = demo_action # shorthand
229 col0 = [('a1', da), ('bbb1', da), ('c1', da)]
230 col1 = [('a2', da), ('bbb2', da)]
231 col2 = [('a3', da), ('b3', da), ('c3', da), ('d4', da), ('d5', da)]
232 col3 = []
233 for i in range(1, 31): col3.append('xxx' + `i`, da)
234 data = [col0, col1, col2, col3]
235 w = open('tablewin.demo', data)
236 gwin.mainloop()
237 return w