Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 1 | # 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 | |
| 17 | import stdwin |
| 18 | import gwin |
Guido van Rossum | 8fd7eee | 1991-12-26 13:06:52 +0000 | [diff] [blame] | 19 | from stdwinevents import * |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 20 | |
| 21 | def 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 | |
| 74 | def 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 | |
| 118 | def 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 | |
| 125 | def 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 | |
| 150 | def 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 | |
| 160 | def 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 | |
| 166 | def arrow(w, type): |
Guido van Rossum | 8fd7eee | 1991-12-26 13:06:52 +0000 | [diff] [blame] | 167 | if type = WC_LEFT: |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 168 | incr = -1, 0 |
Guido van Rossum | 8fd7eee | 1991-12-26 13:06:52 +0000 | [diff] [blame] | 169 | elif type = WC_UP: |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 170 | incr = 0, -1 |
Guido van Rossum | 8fd7eee | 1991-12-26 13:06:52 +0000 | [diff] [blame] | 171 | elif type = WC_RIGHT: |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 172 | incr = 1, 0 |
Guido van Rossum | 8fd7eee | 1991-12-26 13:06:52 +0000 | [diff] [blame] | 173 | elif type = WC_DOWN: |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 174 | 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 | |
| 197 | def 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 | |
| 204 | def hidesel(w, d): # Hide the selection, if shown |
| 205 | if w.selshown: invertsel(w, d) |
| 206 | |
| 207 | def showsel(w, d): # Show the selection, if hidden |
| 208 | if not w.selshown: invertsel(w, d) |
| 209 | |
| 210 | def 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 | |
| 223 | def demo_action(w, string, (icol, irow), detail): # Action function for demo |
| 224 | select(w, (irow, icol)) |
| 225 | |
| 226 | def 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 |