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