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
9 from Carbon
.Appearance
import kThemeStateActive
, kThemeStateInactive
, kThemeStatePressed
12 class List(Wbase
.SelectableWidget
):
14 """Standard list widget."""
18 def __init__(self
, possize
, items
= None, callback
= None, flags
= 0, cols
= 1, typingcasesens
=0):
22 Wbase
.SelectableWidget
.__init
__(self
, possize
)
27 self
._callback
= callback
29 self
.typingcasesens
= typingcasesens
31 self
.lasttime
= Evt
.TickCount()
37 self
.setdrawingmode(0)
39 self
.setdrawingmode(1)
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
,
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
)
57 def adjust(self
, oldbounds
):
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
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))
77 self
._list
.LCellSize((width
/self
._cols
, cellheight
))
79 self
._parentwindow
.wid
.CalcVis()
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()
86 self
.setdrawingmode(0)
88 self
.setselection(sel
)
89 self
.settopcell(topcell
)
90 self
.setdrawingmode(1)
96 Wbase
.SelectableWidget
.close(self
)
101 def setitems(self
, items
):
103 the_list
= self
._list
104 if not self
._parent
or not self
._list
:
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
:
120 isdoubleclick
= self
._list
.LClick(point
, modifiers
)
122 Wbase
.CallbackCall(self
._callback
, 0, isdoubleclick
)
125 def key(self
, char
, event
):
126 (what
, message
, when
, where
, modifiers
) = event
127 sel
= self
.getselection()
129 if char
== Wkeys
.uparrowkey
:
130 if len(sel
) >= 1 and min(sel
) > 0:
131 newselection
= [min(sel
) - 1]
134 elif char
== Wkeys
.downarrowkey
:
135 if len(sel
) >= 1 and max(sel
) < (len(self
.items
) - 1):
136 newselection
= [max(sel
) + 1]
138 newselection
= [len(self
.items
) - 1]
141 if (self
.lasttime
+ self
.timelimit
) < Evt
.TickCount():
143 if self
.typingcasesens
:
144 self
.lasttyping
= self
.lasttyping
+ char
146 self
.lasttyping
= self
.lasttyping
+ string
.lower(char
)
147 self
.lasttime
= Evt
.TickCount()
148 i
= self
.findmatch(self
.lasttyping
)
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
):
159 typingcasesens
= self
.typingcasesens
163 for i
in range(len(items
)):
165 if not typingcasesens
:
167 if tag
<= item
< match
:
173 return len(items
) - 1
175 def domenu_copy(self
, *args
):
176 sel
= self
.getselection()
179 selitems
.append(str(self
.items
[i
]))
180 text
= string
.join(selitems
, '\r')
182 if hasattr(Scrap
, 'PutScrap'):
184 Scrap
.PutScrap('TEXT', text
)
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
):
196 def can_selectall(self
, *args
):
197 return not self
._list
.selFlags
& Lists
.lOnlyOne
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"):
213 ok
, point
= self
._list
.LGetSelect(1, point
)
216 items
.append(point
[1])
217 point
= point
[0], point
[1]+1
220 def setselection(self
, selection
):
221 if not self
._parent
or not self
._list
:
222 self
._sel
= selection
224 set_sel
= self
._list
.LSetSelect
225 for i
in range(len(self
.items
)):
230 self
._list
.LAutoScroll()
232 def getselectedobjects(self
):
233 sel
= self
.getselection()
236 objects
.append(self
.items
[i
])
239 def setselectedobjects(self
, objects
):
243 sel
.append(self
.items
.index(o
))
246 self
.setselection(sel
)
248 def gettopcell(self
):
249 l
, t
, r
, b
= self
._bounds
251 cl
, ct
, cr
, cb
= self
._list
.LRect((0, 0))
253 return (t
- ct
) / cellheight
255 def settopcell(self
, topcell
):
256 top
= self
.gettopcell()
258 self
._list
.LScroll(0, diff
)
260 def draw(self
, visRgn
= None):
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
:
270 def select(self
, onoff
, isclick
= 0):
271 if Wbase
.SelectableWidget
.select(self
, onoff
):
274 self
.drawselframe(onoff
)
276 def activate(self
, onoff
):
277 self
._activated
= onoff
279 self
._list
.LActivate(onoff
)
280 #state = [kThemeStateActive, kThemeStateInactive][not onoff]
281 #App.DrawThemeListBoxFrame(Qd.InsetRect(self._bounds, 1, 1), state)
283 self
.drawselframe(onoff
)
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
):
309 if self
._parent
and self
._list
:
310 self
._list
.LDelRow(b
-a
, a
)
313 def __setslice__(self
, a
, b
, items
):
314 if self
._parent
and self
._list
:
316 the_list
= self
._list
317 self
.setdrawingmode(0)
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.
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)
332 self
.items
[a
:b
] = items
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
):
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
):
361 self
.drawingmode
= self
.drawingmode
- 1
362 if self
.drawingmode
== 0 and self
._list
is not None:
363 self
._list
.LSetDrawingMode(1)
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))
369 Qd
.EraseRect((l
, cb
, cr
, b
))
370 self
._list
.LUpdate(self
._parentwindow
.wid
.GetWindowPort().visRgn
)
371 self
.GetWindow().ValidWindowRect(bounds
)
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."""
384 def createlist(self
):
388 rect
= rect
[0]+1, rect
[1]+1, rect
[2]-16, rect
[3]-1
389 self
._viewbounds
= rect
390 self
._list
= CreateCustomList(
393 (0, self
._cellHeight
),
394 (kListDefUserProcType
, self
.listDefinitionFunc
),
395 self
._parentwindow
.wid
,
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
)
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
):
421 def listDefClose(self
, theList
):
423 def listDefDraw(self
, selected
, cellRect
, theCell
,
424 dataOffset
, dataLen
, theList
):
426 def listDefHighlight(self
, selected
, cellRect
, theCell
,
427 dataOffset
, dataLen
, theList
):
431 class TwoLineList(CustomList
):
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()
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
451 left
, top
, right
, bottom
= cellRect
452 data
= theList
.LGetCell(dataLen
, theCell
)
453 lines
= data
.split("\r")
459 Qd
.MoveTo(int(left
+ 4), int(top
+ ascent
))
460 Qd
.DrawText(line1
, 0, len(line1
))
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)
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()
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
)
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):
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
)
515 if not self
.w
.isvisible():
523 def append(self
, msg
):
524 if not self
.w
.isvisible():
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
):
541 if not self
._parent
or not self
._list
:
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
)):
550 for j
in range(len(row
)):
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"):
563 ok
, point
= self
._list
.LGetSelect(1, point
)
566 items
.append(point
[1])
567 point
= point
[0], point
[1]+1
570 def setselection(self
, selection
):
571 if not self
._parent
or not self
._list
:
572 self
._sel
= selection
574 set_sel
= self
._list
.LSetSelect
575 for i
in range(len(self
.items
)):
576 for j
in range(len(self
.items
[i
])):
581 #self._list.LAutoScroll()