4 from Carbon
import Evt
, Events
, Fm
, Lists
, Qd
, Scrap
, Win
5 from Carbon
.List
import LNew
, CreateCustomList
, GetListPort
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
._list
= LNew(rect
, (0, 0, self
._cols
, 0), (0, 0), self
.LDEF_ID
, self
._parentwindow
.wid
,
49 self
._list
.LSetDrawingMode(0)
50 self
._list
.selFlags
= self
._flags
51 self
.setitems(self
.items
)
52 if hasattr(self
, "_sel"):
53 self
.setselection(self
._sel
)
56 def adjust(self
, oldbounds
):
59 self
.GetWindow().InvalWindowRect(Qd
.InsetRect(oldbounds
, -3, -3))
60 self
.GetWindow().InvalWindowRect(Qd
.InsetRect(self
._bounds
, -3, -3))
62 self
.GetWindow().InvalWindowRect(oldbounds
)
63 self
.GetWindow().InvalWindowRect(self
._bounds
)
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 self
._list
.LSize(width
, height
)
72 # now *why* doesn't the list manager recalc the cellrect???
73 l
, t
, r
, b
= self
._list
.LRect((0,0))
75 self
._list
.LCellSize((width
, cellheight
))
77 self
._parentwindow
.wid
.CalcVis()
79 # oh well, since the list manager doesn't have a LMove call,
80 # we have to make the list all over again...
81 sel
= self
.getselection()
82 topcell
= self
.gettopcell()
84 self
.setdrawingmode(0)
86 self
.setselection(sel
)
87 self
.settopcell(topcell
)
88 self
.setdrawingmode(1)
94 Wbase
.SelectableWidget
.close(self
)
99 def setitems(self
, items
):
101 the_list
= self
._list
102 if not self
._parent
or not self
._list
:
104 self
.setdrawingmode(0)
105 topcell
= self
.gettopcell()
106 the_list
.LDelRow(0, 1)
107 the_list
.LAddRow(len(self
.items
), 0)
108 self_itemrepr
= self
.itemrepr
109 set_cell
= the_list
.LSetCell
110 for i
in range(len(items
)):
111 set_cell(self_itemrepr(items
[i
]), (0, i
))
112 self
.settopcell(topcell
)
113 self
.setdrawingmode(1)
115 def click(self
, point
, modifiers
):
116 if not self
._enabled
:
118 isdoubleclick
= self
._list
.LClick(point
, modifiers
)
120 Wbase
.CallbackCall(self
._callback
, 0, isdoubleclick
)
123 def key(self
, char
, event
):
124 (what
, message
, when
, where
, modifiers
) = event
125 sel
= self
.getselection()
127 if char
== Wkeys
.uparrowkey
:
128 if len(sel
) >= 1 and min(sel
) > 0:
129 newselection
= [min(sel
) - 1]
132 elif char
== Wkeys
.downarrowkey
:
133 if len(sel
) >= 1 and max(sel
) < (len(self
.items
) - 1):
134 newselection
= [max(sel
) + 1]
136 newselection
= [len(self
.items
) - 1]
139 if (self
.lasttime
+ self
.timelimit
) < Evt
.TickCount():
141 if self
.typingcasesens
:
142 self
.lasttyping
= self
.lasttyping
+ char
144 self
.lasttyping
= self
.lasttyping
+ string
.lower(char
)
145 self
.lasttime
= Evt
.TickCount()
146 i
= self
.findmatch(self
.lasttyping
)
148 if modifiers
& Events
.shiftKey
and not self
._list
.selFlags
& Lists
.lOnlyOne
:
149 newselection
= newselection
+ sel
150 self
.setselection(newselection
)
151 self
._list
.LAutoScroll()
152 self
.click((-1, -1), 0)
154 def findmatch(self
, tag
):
157 typingcasesens
= self
.typingcasesens
161 for i
in range(len(items
)):
163 if not typingcasesens
:
165 if tag
<= item
< match
:
171 return len(items
) - 1
173 def domenu_copy(self
, *args
):
174 sel
= self
.getselection()
177 selitems
.append(str(self
.items
[i
]))
178 text
= string
.join(selitems
, '\r')
181 Scrap
.PutScrap('TEXT', text
)
183 def can_copy(self
, *args
):
184 return len(self
.getselection()) <> 0
186 def domenu_selectall(self
, *args
):
189 def can_selectall(self
, *args
):
190 return not self
._list
.selFlags
& Lists
.lOnlyOne
193 if not self
._list
.selFlags
& Lists
.lOnlyOne
:
194 self
.setselection(range(len(self
.items
)))
195 self
._list
.LAutoScroll()
196 self
.click((-1, -1), 0)
198 def getselection(self
):
199 if not self
._parent
or not self
._list
:
200 if hasattr(self
, "_sel"):
206 ok
, point
= self
._list
.LGetSelect(1, point
)
209 items
.append(point
[1])
210 point
= point
[0], point
[1]+1
213 def setselection(self
, selection
):
214 if not self
._parent
or not self
._list
:
215 self
._sel
= selection
217 set_sel
= self
._list
.LSetSelect
218 for i
in range(len(self
.items
)):
223 self
._list
.LAutoScroll()
225 def getselectedobjects(self
):
226 sel
= self
.getselection()
229 objects
.append(self
.items
[i
])
232 def setselectedobjects(self
, objects
):
236 sel
.append(self
.items
.index(o
))
239 self
.setselection(sel
)
241 def gettopcell(self
):
242 l
, t
, r
, b
= self
._bounds
244 cl
, ct
, cr
, cb
= self
._list
.LRect((0, 0))
246 return (t
- ct
) / cellheight
248 def settopcell(self
, topcell
):
249 top
= self
.gettopcell()
251 self
._list
.LScroll(0, diff
)
253 def draw(self
, visRgn
= None):
256 visRgn
= self
._parentwindow
.wid
.GetWindowPort().visRgn
257 self
._list
.LUpdate(visRgn
)
258 App
.DrawThemeListBoxFrame(self
._bounds
, kThemeStateActive
)
259 #if self._selected and self._activated:
260 # self.drawselframe(1)
262 def select(self
, onoff
, isclick
= 0):
263 if Wbase
.SelectableWidget
.select(self
, onoff
):
266 state
= [kThemeStateActive
, kThemeStatePressed
][onoff
]
267 App
.DrawThemeListBoxFrame(self
._bounds
, kThemeStateActive
)
268 #self.drawselframe(onoff)
270 def activate(self
, onoff
):
271 self
._activated
= onoff
273 self
._list
.LActivate(onoff
)
275 # self.drawselframe(onoff)
280 def itemrepr(self
, item
):
281 return str(item
)[:255]
283 def __getitem__(self
, index
):
284 return self
.items
[index
]
286 def __setitem__(self
, index
, item
):
287 if self
._parent
and self
._list
:
288 self
._list
.LSetCell(self
.itemrepr(item
), (0, index
))
289 self
.items
[index
] = item
291 def __delitem__(self
, index
):
292 if self
._parent
and self
._list
:
293 self
._list
.LDelRow(1, index
)
294 del self
.items
[index
]
296 def __getslice__(self
, a
, b
):
297 return self
.items
[a
:b
]
299 def __delslice__(self
, a
, b
):
301 if self
._parent
and self
._list
:
302 self
._list
.LDelRow(b
-a
, a
)
305 def __setslice__(self
, a
, b
, items
):
306 if self
._parent
and self
._list
:
308 the_list
= self
._list
309 self
.setdrawingmode(0)
311 if b
> len(self
.items
):
312 # fix for new 1.5 "feature" where b is sys.maxint instead of len(self)...
313 # LDelRow doesn't like maxint.
315 the_list
.LDelRow(b
-a
, a
)
316 the_list
.LAddRow(l
, a
)
317 self_itemrepr
= self
.itemrepr
318 set_cell
= the_list
.LSetCell
319 for i
in range(len(items
)):
320 set_cell(self_itemrepr(items
[i
]), (0, i
+ a
))
321 self
.items
[a
:b
] = items
322 self
.setdrawingmode(1)
324 self
.items
[a
:b
] = items
327 return len(self
.items
)
329 def append(self
, item
):
330 if self
._parent
and self
._list
:
331 index
= len(self
.items
)
332 self
._list
.LAddRow(1, index
)
333 self
._list
.LSetCell(self
.itemrepr(item
), (0, index
))
334 self
.items
.append(item
)
336 def remove(self
, item
):
337 index
= self
.items
.index(item
)
338 self
.__delitem
__(index
)
340 def index(self
, item
):
341 return self
.items
.index(item
)
343 def insert(self
, index
, item
):
346 if self
._parent
and self
._list
:
347 self
._list
.LAddRow(1, index
)
348 self
._list
.LSetCell(self
.itemrepr(item
), (0, index
))
349 self
.items
.insert(index
, item
)
351 def setdrawingmode(self
, onoff
):
353 self
.drawingmode
= self
.drawingmode
- 1
354 if self
.drawingmode
== 0 and self
._list
is not None:
355 self
._list
.LSetDrawingMode(1)
357 bounds
= l
, t
, r
, b
= Qd
.InsetRect(self
._bounds
, 1, 1)
358 cl
, ct
, cr
, cb
= self
._list
.LRect((0, len(self
.items
)-1))
361 Qd
.EraseRect((l
, cb
, cr
, b
))
362 self
._list
.LUpdate(self
._parentwindow
.wid
.GetWindowPort().visRgn
)
363 self
.GetWindow().ValidWindowRect(bounds
)
365 if self
.drawingmode
== 0 and self
._list
is not None:
366 self
._list
.LSetDrawingMode(0)
367 self
.drawingmode
= self
.drawingmode
+ 1
370 class CustomList(List
):
372 """Base class for writing custom list definitions."""
376 def createlist(self
):
380 rect
= rect
[0]+1, rect
[1]+1, rect
[2]-16, rect
[3]-1
381 self
._list
= CreateCustomList(
384 (0, self
._cellHeight
),
385 (kListDefUserProcType
, self
.listDefinitionFunc
),
386 self
._parentwindow
.wid
,
389 self
._list
.LSetDrawingMode(0)
390 self
._list
.selFlags
= self
._flags
391 self
.setitems(self
.items
)
392 if hasattr(self
, "_sel"):
393 self
.setselection(self
._sel
)
396 def listDefinitionFunc(self
, message
, selected
, cellRect
, theCell
,
397 dataOffset
, dataLen
, theList
):
398 """The LDEF message dispatcher routine, no need to override."""
399 if message
== lInitMsg
:
400 self
.listDefInit(theList
)
401 elif message
== lDrawMsg
:
402 self
.listDefDraw(selected
, cellRect
, theCell
,
403 dataOffset
, dataLen
, theList
)
404 elif message
== lHiliteMsg
:
405 self
.listDefHighlight(selected
, cellRect
, theCell
,
406 dataOffset
, dataLen
, theList
)
407 elif message
== lCloseMsg
:
408 self
.listDefClose(theList
)
410 def listDefInit(self
, theList
):
412 def listDefClose(self
, theList
):
414 def listDefDraw(self
, selected
, cellRect
, theCell
,
415 dataOffset
, dataLen
, theList
):
417 def listDefHighlight(self
, selected
, cellRect
, theCell
,
418 dataOffset
, dataLen
, theList
):
422 class TwoLineList(CustomList
):
426 def listDefDraw(self
, selected
, cellRect
, theCell
,
427 dataOffset
, dataLen
, theList
):
428 savedPort
= Qd
.GetPort()
429 Qd
.SetPort(GetListPort(theList
))
430 savedClip
= Qd
.NewRgn()
431 Qd
.GetClip(savedClip
)
432 Qd
.ClipRect(cellRect
)
433 savedPenState
= Qd
.GetPenState()
435 Qd
.EraseRect(cellRect
)
437 #draw the cell if it contains data
438 ascent
, descent
, leading
, size
, hm
= Fm
.FontMetrics()
439 linefeed
= ascent
+ descent
+ leading
442 left
, top
, right
, bottom
= cellRect
443 data
= theList
.LGetCell(dataLen
, theCell
)
444 lines
= data
.split("\r")
450 Qd
.MoveTo(left
+ 4, top
+ ascent
)
451 Qd
.DrawText(line1
, 0, len(line1
))
453 Qd
.MoveTo(left
+ 4, top
+ ascent
+ linefeed
)
454 Qd
.DrawText(line2
, 0, len(line2
))
455 Qd
.PenPat("\x11\x11\x11\x11\x11\x11\x11\x11")
456 bottom
= top
+ theList
.cellSize
[1]
457 Qd
.MoveTo(left
, bottom
- 1)
458 Qd
.LineTo(right
, bottom
- 1)
460 self
.listDefHighlight(selected
, cellRect
, theCell
,
461 dataOffset
, dataLen
, theList
)
462 #restore graphics environment
463 Qd
.SetPort(savedPort
)
464 Qd
.SetClip(savedClip
)
465 Qd
.DisposeRgn(savedClip
)
466 Qd
.SetPenState(savedPenState
)
468 def listDefHighlight(self
, selected
, cellRect
, theCell
,
469 dataOffset
, dataLen
, theList
):
470 savedPort
= Qd
.GetPort()
471 Qd
.SetPort(GetListPort(theList
))
472 savedClip
= Qd
.NewRgn()
473 Qd
.GetClip(savedClip
)
474 Qd
.ClipRect(cellRect
)
475 savedPenState
= Qd
.GetPenState()
477 Qd
.PenMode(hilitetransfermode
)
478 Qd
.PaintRect(cellRect
)
480 #restore graphics environment
481 Qd
.SetPort(savedPort
)
482 Qd
.SetClip(savedClip
)
483 Qd
.DisposeRgn(savedClip
)
484 Qd
.SetPenState(savedPenState
)
489 """Simple results window. The user cannot make this window go away completely:
490 closing it will just hide it. It will remain in the windows list. The owner of this window
491 should call the done() method to indicate it's done with it.
494 def __init__(self
, possize
=None, title
="Results", callback
=None):
498 self
.w
= W
.Window(possize
, title
, minsize
=(200, 100))
499 self
.w
.results
= W
.TwoLineList((-1, -1, 1, -14), callback
=None)
500 self
.w
.bind("<close>", self
.hide
)
506 if not self
.w
.isvisible():
514 def append(self
, msg
):
515 if not self
.w
.isvisible():
518 msg
= string
.replace(msg
, '\n', '\r')
519 self
.w
.results
.append(msg
)
520 self
.w
.results
.setselection([len(self
.w
.results
)-1])
522 def __getattr__(self
, attr
):
523 return getattr(self
.w
.results
, attr
)
526 class MultiList(List
):
528 """XXX Experimantal!!!"""
530 def setitems(self
, items
):
532 if not self
._parent
or not self
._list
:
534 self
._list
.LDelRow(0, 1)
535 self
.setdrawingmode(0)
536 self
._list
.LAddRow(len(self
.items
), 0)
537 self_itemrepr
= self
.itemrepr
538 set_cell
= self
._list
.LSetCell
539 for i
in range(len(items
)):
541 for j
in range(len(row
)):
543 set_cell(self_itemrepr(item
), (j
, i
))
544 self
.setdrawingmode(1)
546 def getselection(self
):
547 if not self
._parent
or not self
._list
:
548 if hasattr(self
, "_sel"):
554 ok
, point
= self
._list
.LGetSelect(1, point
)
557 items
.append(point
[1])
558 point
= point
[0], point
[1]+1
561 def setselection(self
, selection
):
562 if not self
._parent
or not self
._list
:
563 self
._sel
= selection
565 set_sel
= self
._list
.LSetSelect
566 for i
in range(len(self
.items
)):
571 #self._list.LAutoScroll()