Move setting of ioready 'wait' earlier in call chain, to
[python/dscho.git] / Mac / Tools / IDE / Wlists.py
blob1b66a8bab36f245147b84d99c575cd34582b4108
1 import Wbase
2 import Wkeys
3 import string
4 from Carbon import Evt, Events, Fm, Lists, Qd, Scrap, Win
5 from Carbon.List import LNew, CreateCustomList
6 from Carbon.Lists import kListDefUserProcType, lInitMsg, lDrawMsg, lHiliteMsg, lCloseMsg
7 from Carbon.QuickDraw import hilitetransfermode
8 from Carbon import App
9 from Carbon.Appearance import kThemeStateActive, kThemeStateInactive, kThemeStatePressed
12 class List(Wbase.SelectableWidget):
14 """Standard list widget."""
16 LDEF_ID = 0
18 def __init__(self, possize, items = None, callback = None, flags = 0, cols = 1, typingcasesens=0):
19 if items is None:
20 items = []
21 self.items = items
22 Wbase.SelectableWidget.__init__(self, possize)
23 self._selected = 0
24 self._enabled = 1
25 self._list = None
26 self._cols = cols
27 self._callback = callback
28 self._flags = flags
29 self.typingcasesens = typingcasesens
30 self.lasttyping = ""
31 self.lasttime = Evt.TickCount()
32 self.timelimit = 30
33 self.setitems(items)
34 self.drawingmode = 0
36 def open(self):
37 self.setdrawingmode(0)
38 self.createlist()
39 self.setdrawingmode(1)
41 def createlist(self):
42 self._calcbounds()
43 self.SetPort()
44 rect = self._bounds
45 rect = rect[0]+1, rect[1]+1, rect[2]-16, rect[3]-1
46 self._viewbounds = rect
47 self._list = LNew(rect, (0, 0, self._cols, 0), (0, 0), self.LDEF_ID, self._parentwindow.wid,
48 0, 1, 0, 1)
49 if self.drawingmode:
50 self._list.LSetDrawingMode(0)
51 self._list.selFlags = self._flags
52 self.setitems(self.items)
53 if hasattr(self, "_sel"):
54 self.setselection(self._sel)
55 del self._sel
57 def adjust(self, oldbounds):
58 self.SetPort()
59 # Appearance frames are drawn outside the specified bounds,
60 # so we always need to outset the invalidated area.
61 self.GetWindow().InvalWindowRect(Qd.InsetRect(oldbounds, -3, -3))
62 self.GetWindow().InvalWindowRect(Qd.InsetRect(self._bounds, -3, -3))
64 if oldbounds[:2] == self._bounds[:2]:
65 # set visRgn to empty, to prevent nasty drawing side effect of LSize()
66 Qd.RectRgn(self._parentwindow.wid.GetWindowPort().visRgn, (0, 0, 0, 0))
67 # list still has the same upper/left coordinates, use LSize
68 l, t, r, b = self._bounds
69 width = r - l - 17
70 height = b - t - 2
71 vl, vt, vr, vb = self._viewbounds
72 self._viewbounds = vl, vt, vl + width, vt + height
73 self._list.LSize(width, height)
74 # now *why* doesn't the list manager recalc the cellrect???
75 l, t, r, b = self._list.LRect((0,0))
76 cellheight = b - t
77 self._list.LCellSize((width/self._cols, cellheight))
78 # reset visRgn
79 self._parentwindow.wid.CalcVis()
80 else:
81 # oh well, since the list manager doesn't have a LMove call,
82 # we have to make the list all over again...
83 sel = self.getselection()
84 topcell = self.gettopcell()
85 self._list = None
86 self.setdrawingmode(0)
87 self.createlist()
88 self.setselection(sel)
89 self.settopcell(topcell)
90 self.setdrawingmode(1)
92 def close(self):
93 self._list = None
94 self._callback = None
95 self.items = []
96 Wbase.SelectableWidget.close(self)
98 def set(self, items):
99 self.setitems(items)
101 def setitems(self, items):
102 self.items = items
103 the_list = self._list
104 if not self._parent or not self._list:
105 return
106 self.setdrawingmode(0)
107 topcell = self.gettopcell()
108 the_list.LDelRow(0, 1)
109 the_list.LAddRow(len(self.items), 0)
110 self_itemrepr = self.itemrepr
111 set_cell = the_list.LSetCell
112 for i in range(len(items)):
113 set_cell(self_itemrepr(items[i]), (0, i))
114 self.settopcell(topcell)
115 self.setdrawingmode(1)
117 def click(self, point, modifiers):
118 if not self._enabled:
119 return
120 isdoubleclick = self._list.LClick(point, modifiers)
121 if self._callback:
122 Wbase.CallbackCall(self._callback, 0, isdoubleclick)
123 return 1
125 def key(self, char, event):
126 (what, message, when, where, modifiers) = event
127 sel = self.getselection()
128 newselection = []
129 if char == Wkeys.uparrowkey:
130 if len(sel) >= 1 and min(sel) > 0:
131 newselection = [min(sel) - 1]
132 else:
133 newselection = [0]
134 elif char == Wkeys.downarrowkey:
135 if len(sel) >= 1 and max(sel) < (len(self.items) - 1):
136 newselection = [max(sel) + 1]
137 else:
138 newselection = [len(self.items) - 1]
139 else:
140 modifiers = 0
141 if (self.lasttime + self.timelimit) < Evt.TickCount():
142 self.lasttyping = ""
143 if self.typingcasesens:
144 self.lasttyping = self.lasttyping + char
145 else:
146 self.lasttyping = self.lasttyping + string.lower(char)
147 self.lasttime = Evt.TickCount()
148 i = self.findmatch(self.lasttyping)
149 newselection = [i]
150 if modifiers & Events.shiftKey and not self._list.selFlags & Lists.lOnlyOne:
151 newselection = newselection + sel
152 self.setselection(newselection)
153 self._list.LAutoScroll()
154 self.click((-1, -1), 0)
156 def findmatch(self, tag):
157 lower = string.lower
158 items = self.items
159 typingcasesens = self.typingcasesens
160 taglen = len(tag)
161 match = '\377' * 100
162 match_i = -1
163 for i in range(len(items)):
164 item = str(items[i])
165 if not typingcasesens:
166 item = lower(item)
167 if tag <= item < match:
168 match = item
169 match_i = i
170 if match_i >= 0:
171 return match_i
172 else:
173 return len(items) - 1
175 def domenu_copy(self, *args):
176 sel = self.getselection()
177 selitems = []
178 for i in sel:
179 selitems.append(str(self.items[i]))
180 text = string.join(selitems, '\r')
181 if text:
182 if hasattr(Scrap, 'PutScrap'):
183 Scrap.ZeroScrap()
184 Scrap.PutScrap('TEXT', text)
185 else:
186 Scrap.ClearCurrentScrap()
187 sc = Scrap.GetCurrentScrap()
188 sc.PutScrapFlavor('TEXT', 0, text)
190 def can_copy(self, *args):
191 return len(self.getselection()) <> 0
193 def domenu_selectall(self, *args):
194 self.selectall()
196 def can_selectall(self, *args):
197 return not self._list.selFlags & Lists.lOnlyOne
199 def selectall(self):
200 if not self._list.selFlags & Lists.lOnlyOne:
201 self.setselection(range(len(self.items)))
202 self._list.LAutoScroll()
203 self.click((-1, -1), 0)
205 def getselection(self):
206 if not self._parent or not self._list:
207 if hasattr(self, "_sel"):
208 return self._sel
209 return []
210 items = []
211 point = (0,0)
212 while 1:
213 ok, point = self._list.LGetSelect(1, point)
214 if not ok:
215 break
216 items.append(point[1])
217 point = point[0], point[1]+1
218 return items
220 def setselection(self, selection):
221 if not self._parent or not self._list:
222 self._sel = selection
223 return
224 set_sel = self._list.LSetSelect
225 for i in range(len(self.items)):
226 if i in selection:
227 set_sel(1, (0, i))
228 else:
229 set_sel(0, (0, i))
230 self._list.LAutoScroll()
232 def getselectedobjects(self):
233 sel = self.getselection()
234 objects = []
235 for i in sel:
236 objects.append(self.items[i])
237 return objects
239 def setselectedobjects(self, objects):
240 sel = []
241 for o in objects:
242 try:
243 sel.append(self.items.index(o))
244 except:
245 pass
246 self.setselection(sel)
248 def gettopcell(self):
249 l, t, r, b = self._bounds
250 t = t + 1
251 cl, ct, cr, cb = self._list.LRect((0, 0))
252 cellheight = cb - ct
253 return (t - ct) / cellheight
255 def settopcell(self, topcell):
256 top = self.gettopcell()
257 diff = topcell - top
258 self._list.LScroll(0, diff)
260 def draw(self, visRgn = None):
261 if self._visible:
262 if not visRgn:
263 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
264 self._list.LUpdate(visRgn)
265 state = [kThemeStateActive, kThemeStateInactive][not self._activated]
266 App.DrawThemeListBoxFrame(Qd.InsetRect(self._bounds, 1, 1), state)
267 if self._selected and self._activated:
268 self.drawselframe(1)
270 def select(self, onoff, isclick = 0):
271 if Wbase.SelectableWidget.select(self, onoff):
272 return
273 self.SetPort()
274 self.drawselframe(onoff)
276 def activate(self, onoff):
277 self._activated = onoff
278 if self._visible:
279 self._list.LActivate(onoff)
280 #state = [kThemeStateActive, kThemeStateInactive][not onoff]
281 #App.DrawThemeListBoxFrame(Qd.InsetRect(self._bounds, 1, 1), state)
282 if self._selected:
283 self.drawselframe(onoff)
285 def get(self):
286 return self.items
288 def itemrepr(self, item):
289 return str(item)[:255]
291 def __getitem__(self, index):
292 return self.items[index]
294 def __setitem__(self, index, item):
295 if self._parent and self._list:
296 self._list.LSetCell(self.itemrepr(item), (0, index))
297 self.items[index] = item
299 def __delitem__(self, index):
300 if self._parent and self._list:
301 self._list.LDelRow(1, index)
302 del self.items[index]
304 def __getslice__(self, a, b):
305 return self.items[a:b]
307 def __delslice__(self, a, b):
308 if b-a:
309 if self._parent and self._list:
310 self._list.LDelRow(b-a, a)
311 del self.items[a:b]
313 def __setslice__(self, a, b, items):
314 if self._parent and self._list:
315 l = len(items)
316 the_list = self._list
317 self.setdrawingmode(0)
318 if b-a:
319 if b > len(self.items):
320 # fix for new 1.5 "feature" where b is sys.maxint instead of len(self)...
321 # LDelRow doesn't like maxint.
322 b = len(self.items)
323 the_list.LDelRow(b-a, a)
324 the_list.LAddRow(l, a)
325 self_itemrepr = self.itemrepr
326 set_cell = the_list.LSetCell
327 for i in range(len(items)):
328 set_cell(self_itemrepr(items[i]), (0, i + a))
329 self.items[a:b] = items
330 self.setdrawingmode(1)
331 else:
332 self.items[a:b] = items
334 def __len__(self):
335 return len(self.items)
337 def append(self, item):
338 if self._parent and self._list:
339 index = len(self.items)
340 self._list.LAddRow(1, index)
341 self._list.LSetCell(self.itemrepr(item), (0, index))
342 self.items.append(item)
344 def remove(self, item):
345 index = self.items.index(item)
346 self.__delitem__(index)
348 def index(self, item):
349 return self.items.index(item)
351 def insert(self, index, item):
352 if index < 0:
353 index = 0
354 if self._parent and self._list:
355 self._list.LAddRow(1, index)
356 self._list.LSetCell(self.itemrepr(item), (0, index))
357 self.items.insert(index, item)
359 def setdrawingmode(self, onoff):
360 if onoff:
361 self.drawingmode = self.drawingmode - 1
362 if self.drawingmode == 0 and self._list is not None:
363 self._list.LSetDrawingMode(1)
364 if self._visible:
365 bounds = l, t, r, b = Qd.InsetRect(self._bounds, 1, 1)
366 cl, ct, cr, cb = self._list.LRect((0, len(self.items)-1))
367 if cb < b:
368 self.SetPort()
369 Qd.EraseRect((l, cb, cr, b))
370 self._list.LUpdate(self._parentwindow.wid.GetWindowPort().visRgn)
371 self.GetWindow().ValidWindowRect(bounds)
372 else:
373 if self.drawingmode == 0 and self._list is not None:
374 self._list.LSetDrawingMode(0)
375 self.drawingmode = self.drawingmode + 1
378 class CustomList(List):
380 """Base class for writing custom list definitions."""
382 _cellHeight = 0
384 def createlist(self):
385 self._calcbounds()
386 self.SetPort()
387 rect = self._bounds
388 rect = rect[0]+1, rect[1]+1, rect[2]-16, rect[3]-1
389 self._viewbounds = rect
390 self._list = CreateCustomList(
391 rect,
392 (0, 0, 1, 0),
393 (0, self._cellHeight),
394 (kListDefUserProcType, self.listDefinitionFunc),
395 self._parentwindow.wid,
396 0, 1, 0, 1)
397 if self.drawingmode:
398 self._list.LSetDrawingMode(0)
399 self._list.selFlags = self._flags
400 self.setitems(self.items)
401 if hasattr(self, "_sel"):
402 self.setselection(self._sel)
403 del self._sel
405 def listDefinitionFunc(self, message, selected, cellRect, theCell,
406 dataOffset, dataLen, theList):
407 """The LDEF message dispatcher routine, no need to override."""
408 if message == lInitMsg:
409 self.listDefInit(theList)
410 elif message == lDrawMsg:
411 self.listDefDraw(selected, cellRect, theCell,
412 dataOffset, dataLen, theList)
413 elif message == lHiliteMsg:
414 self.listDefHighlight(selected, cellRect, theCell,
415 dataOffset, dataLen, theList)
416 elif message == lCloseMsg:
417 self.listDefClose(theList)
419 def listDefInit(self, theList):
420 pass
421 def listDefClose(self, theList):
422 pass
423 def listDefDraw(self, selected, cellRect, theCell,
424 dataOffset, dataLen, theList):
425 pass
426 def listDefHighlight(self, selected, cellRect, theCell,
427 dataOffset, dataLen, theList):
428 pass
431 class TwoLineList(CustomList):
433 _cellHeight = 28
435 def listDefDraw(self, selected, cellRect, theCell,
436 dataOffset, dataLen, theList):
437 savedPort = Qd.GetPort()
438 Qd.SetPort(theList.GetListPort())
439 savedClip = Qd.NewRgn()
440 Qd.GetClip(savedClip)
441 Qd.ClipRect(cellRect)
442 savedPenState = Qd.GetPenState()
443 Qd.PenNormal()
444 Qd.EraseRect(cellRect)
446 #draw the cell if it contains data
447 ascent, descent, leading, size, hm = Fm.FontMetrics()
448 linefeed = ascent + descent + leading
450 if dataLen:
451 left, top, right, bottom = cellRect
452 data = theList.LGetCell(dataLen, theCell)
453 lines = data.split("\r")
454 line1 = lines[0]
455 if len(lines) > 1:
456 line2 = lines[1]
457 else:
458 line2 = ""
459 Qd.MoveTo(int(left + 4), int(top + ascent))
460 Qd.DrawText(line1, 0, len(line1))
461 if line2:
462 Qd.MoveTo(int(left + 4), int(top + ascent + linefeed))
463 Qd.DrawText(line2, 0, len(line2))
464 Qd.PenPat("\x11\x11\x11\x11\x11\x11\x11\x11")
465 bottom = top + theList.cellSize[1]
466 Qd.MoveTo(left, bottom - 1)
467 Qd.LineTo(right, bottom - 1)
468 if selected:
469 self.listDefHighlight(selected, cellRect, theCell,
470 dataOffset, dataLen, theList)
471 #restore graphics environment
472 Qd.SetPort(savedPort)
473 Qd.SetClip(savedClip)
474 Qd.DisposeRgn(savedClip)
475 Qd.SetPenState(savedPenState)
477 def listDefHighlight(self, selected, cellRect, theCell,
478 dataOffset, dataLen, theList):
479 savedPort = Qd.GetPort()
480 Qd.SetPort(theList.GetListPort())
481 savedClip = Qd.NewRgn()
482 Qd.GetClip(savedClip)
483 Qd.ClipRect(cellRect)
484 savedPenState = Qd.GetPenState()
485 Qd.PenNormal()
486 Qd.PenMode(hilitetransfermode)
487 Qd.PaintRect(cellRect)
489 #restore graphics environment
490 Qd.SetPort(savedPort)
491 Qd.SetClip(savedClip)
492 Qd.DisposeRgn(savedClip)
493 Qd.SetPenState(savedPenState)
496 class ResultsWindow:
498 """Simple results window. The user cannot make this window go away completely:
499 closing it will just hide it. It will remain in the windows list. The owner of this window
500 should call the done() method to indicate it's done with it.
503 def __init__(self, possize=None, title="Results", callback=None):
504 import W
505 if possize is None:
506 possize = (500, 200)
507 self.w = W.Window(possize, title, minsize=(200, 100))
508 self.w.results = W.TwoLineList((-1, -1, 1, -14), callback=None)
509 self.w.bind("<close>", self.hide)
510 self.w.open()
511 self._done = 0
513 def done(self):
514 self._done = 1
515 if not self.w.isvisible():
516 self.w.close()
518 def hide(self):
519 if not self._done:
520 self.w.show(0)
521 return -1
523 def append(self, msg):
524 if not self.w.isvisible():
525 self.w.show(1)
526 self.w.select()
527 msg = string.replace(msg, '\n', '\r')
528 self.w.results.append(msg)
529 self.w.results.setselection([len(self.w.results)-1])
531 def __getattr__(self, attr):
532 return getattr(self.w.results, attr)
535 class MultiList(List):
537 """XXX Experimantal!!!"""
539 def setitems(self, items):
540 self.items = items
541 if not self._parent or not self._list:
542 return
543 self._list.LDelRow(0, 1)
544 self.setdrawingmode(0)
545 self._list.LAddRow(len(self.items), 0)
546 self_itemrepr = self.itemrepr
547 set_cell = self._list.LSetCell
548 for i in range(len(items)):
549 row = items[i]
550 for j in range(len(row)):
551 item = row[j]
552 set_cell(self_itemrepr(item), (j, i))
553 self.setdrawingmode(1)
555 def getselection(self):
556 if not self._parent or not self._list:
557 if hasattr(self, "_sel"):
558 return self._sel
559 return []
560 items = []
561 point = (0,0)
562 while 1:
563 ok, point = self._list.LGetSelect(1, point)
564 if not ok:
565 break
566 items.append(point[1])
567 point = point[0], point[1]+1
568 return items
570 def setselection(self, selection):
571 if not self._parent or not self._list:
572 self._sel = selection
573 return
574 set_sel = self._list.LSetSelect
575 for i in range(len(self.items)):
576 for j in range(len(self.items[i])):
577 if i in selection:
578 set_sel(1, (j, i))
579 else:
580 set_sel(0, (j, i))
581 #self._list.LAutoScroll()