7 from SpecialKeys
import *
10 WidgetsError
= "WidgetsError"
18 def __init__(self
, possize
):
20 self
._widgetsdict
= {}
21 self
._possize
= possize
29 self
._parentwindow
= None
31 self
._backcolor
= None
33 def show(self
, onoff
):
37 if self
._visible
and self
._backcolor
:
38 penstate
= Qd
.GetPenState()
39 Qd
.RGBForeColor(self
._backcolor
)
40 Qd
.FrameRect(self
._bounds
)
41 Qd
.RGBForeColor((0, 0, 0))
42 Qd
.SetPenState(penstate
)
44 for w
in self
._widgets
:
49 Qd
.EraseRect(self
._bounds
)
51 def draw(self
, visRgn
= None):
53 # draw your stuff here
62 def move(self
, x
, y
= None):
66 if type(self
._possize
) <> TupleType
:
67 raise WidgetsError
, "can't move widget with bounds function"
68 l
, t
, r
, b
= self
._possize
69 self
.resize(x
, y
, r
, b
)
71 def rmove(self
, x
, y
= None):
75 if type(self
._possize
) <> TupleType
:
76 raise WidgetsError
, "can't move widget with bounds function"
77 l
, t
, r
, b
= self
._possize
78 self
.resize(l
+ x
, t
+ y
, r
, b
)
80 def resize(self
, *args
):
83 if type(args
[0]) == FunctionType
or type(args
[0]) == MethodType
:
84 self
._possize
= args
[0]
86 apply(self
.resize
, args
[0])
88 self
._possize
= (0, 0) + args
92 raise TypeError, "wrong number of arguments"
99 #print "xxx Closing Widget"
104 del self
._parentwindow
106 def bind(self
, key
, callback
):
107 """bind a key or an 'event' to a callback"""
109 self
._bindings
[key
] = callback
110 elif self
._bindings
.has_key(key
):
111 del self
._bindings
[key
]
113 def adjust(self
, oldbounds
):
115 Win
.InvalRect(oldbounds
)
116 Win
.InvalRect(self
._bounds
)
118 def _calcbounds(self
):
119 oldbounds
= self
._bounds
120 pl
, pt
, pr
, pb
= self
._parent
._bounds
121 if callable(self
._possize
):
124 self
._bounds
= Qd
.OffsetRect(self
._possize
(width
, height
), pl
, pt
)
126 l
, t
, r
, b
= self
._possize
143 self
._bounds
= (l
, t
, r
, b
)
144 if oldbounds
and oldbounds
<> self
._bounds
:
145 self
.adjust(oldbounds
)
146 for w
in self
._widgets
:
149 def test(self
, point
):
150 if Qd
.PtInRect(point
, self
._bounds
):
153 def click(self
, point
, modifiers
):
156 def findwidget(self
, point
, onlyenabled
= 1):
158 for w
in self
._widgets
:
159 widget
= w
.findwidget(point
)
160 if widget
is not None:
162 if self
._enabled
or not onlyenabled
:
165 def forall(self
, methodname
, *args
):
166 for w
in self
._widgets
:
167 rv
= apply(w
.forall
, (methodname
,) + args
)
170 if self
._bindings
.has_key("<" + methodname
+ ">"):
171 callback
= self
._bindings
["<" + methodname
+ ">"]
172 rv
= apply(callback
, args
)
175 if hasattr(self
, methodname
):
176 method
= getattr(self
, methodname
)
177 return apply(method
, args
)
179 def forall_butself(self
, methodname
, *args
):
180 for w
in self
._widgets
:
181 rv
= apply(w
.forall
, (methodname
,) + args
)
185 def forall_frombottom(self
, methodname
, *args
):
186 if self
._bindings
.has_key("<" + methodname
+ ">"):
187 callback
= self
._bindings
["<" + methodname
+ ">"]
188 rv
= apply(callback
, args
)
191 if hasattr(self
, methodname
):
192 method
= getattr(self
, methodname
)
193 rv
= apply(method
, args
)
196 for w
in self
._widgets
:
197 rv
= apply(w
.forall_frombottom
, (methodname
,) + args
)
201 def _addwidget(self
, key
, widget
):
202 if widget
in self
._widgets
:
203 raise ValueError, "duplicate widget"
204 if self
._widgetsdict
.has_key(key
):
205 self
._removewidget
(key
)
206 self
._widgets
.append(widget
)
207 self
._widgetsdict
[key
] = widget
208 widget
._parent
= self
209 self
._setparentwindow
(widget
)
210 if self
._parentwindow
and self
._parentwindow
.wid
:
211 widget
.forall_frombottom("open")
212 Win
.InvalRect(widget
._bounds
)
214 def _setparentwindow(self
, widget
):
215 widget
._parentwindow
= self
._parentwindow
216 for w
in widget
._widgets
:
217 self
._setparentwindow
(w
)
219 def _removewidget(self
, key
):
220 if not self
._widgetsdict
.has_key(key
):
221 raise KeyError, "no widget with key " + `key`
222 widget
= self
._widgetsdict
[key
]
223 for k
in widget
._widgetsdict
.keys():
224 widget
._removewidget
(k
)
225 if self
._parentwindow
._currentwidget
== widget
:
227 self
._parentwindow
._currentwidget
= None
229 Win
.InvalRect(widget
._bounds
)
231 del self
._widgetsdict
[key
]
232 self
._widgets
.remove(widget
)
234 def __setattr__(self
, attr
, value
):
235 if type(value
) == InstanceType
and HasBaseClass(value
, Widget
) and \
236 attr
not in ("_currentwidget", "_lastrollover",
237 "_parent", "_parentwindow", "_defaultbutton"):
238 if hasattr(self
, attr
):
239 raise ValueError, "Can't replace existing attribute: " + attr
240 self
._addwidget
(attr
, value
)
241 self
.__dict
__[attr
] = value
243 def __delattr__(self
, attr
):
244 if attr
== "_widgetsdict":
245 raise AttributeError, "cannot delete attribute _widgetsdict"
246 if self
._widgetsdict
.has_key(attr
):
247 self
._removewidget
(attr
)
248 if self
.__dict
__.has_key(attr
):
249 del self
.__dict
__[attr
]
250 elif self
.__dict
__.has_key(attr
):
251 del self
.__dict
__[attr
]
253 raise AttributeError, attr
255 def __setitem__(self
, key
, value
):
256 self
._addwidget
(key
, value
)
258 def __getitem__(self
, key
):
259 if not self
._widgetsdict
.has_key(key
):
261 return self
._widgetsdict
[key
]
263 def __delitem__(self
, key
):
264 self
._removewidget
(key
)
267 self
._parentwindow
.SetPort()
271 print "%s instance deleted" % self
.__class
__.__name
__
273 def _drawbounds(self
):
274 Qd
.FrameRect(self
._bounds
)
277 class ClickableWidget(Widget
):
279 def click(self
, point
, modifiers
):
282 def enable(self
, onoff
):
283 self
._enabled
= onoff
289 return CallbackCall(self
._callback
, 1)
292 class SelectableWidget(ClickableWidget
):
296 def select(self
, onoff
, isclick
= 0):
297 if onoff
== self
._selected
:
299 if self
._bindings
.has_key("<select>"):
300 callback
= self
._bindings
["<select>"]
303 self
._selected
= onoff
305 if self
._parentwindow
._currentwidget
is not None:
306 self
._parentwindow
._currentwidget
.select(0)
307 self
._parentwindow
._currentwidget
= self
309 self
._parentwindow
._currentwidget
= None
311 def key(self
, char
, event
):
314 def drawselframe(self
, onoff
):
315 if not self
._parentwindow
._hasselframes
:
317 thickrect
= Qd
.InsetRect(self
._bounds
, -3, -3)
318 state
= Qd
.GetPenState()
321 Qd
.PenPat(Qd
.qd
.black
)
323 Qd
.PenPat(Qd
.qd
.white
)
324 Qd
.FrameRect(thickrect
)
325 Qd
.SetPenState(state
)
327 def adjust(self
, oldbounds
):
330 Win
.InvalRect(Qd
.InsetRect(oldbounds
, -3, -3))
331 Win
.InvalRect(Qd
.InsetRect(self
._bounds
, -3, -3))
333 Win
.InvalRect(oldbounds
)
334 Win
.InvalRect(self
._bounds
)
339 def __init__(self
, possize
, thickness
= 1):
340 Widget
.__init
__(self
, possize
)
341 self
._thickness
= thickness
348 def draw(self
, visRgn
= None):
350 Qd
.PaintRect(self
._bounds
)
352 def _drawbounds(self
):
355 class HorizontalLine(_Line
):
357 def _calcbounds(self
):
358 Widget
._calcbounds
(self
)
359 l
, t
, r
, b
= self
._bounds
360 self
._bounds
= l
, t
, r
, t
+ self
._thickness
362 class VerticalLine(_Line
):
364 def _calcbounds(self
):
365 Widget
._calcbounds
(self
)
366 l
, t
, r
, b
= self
._bounds
367 self
._bounds
= l
, t
, l
+ self
._thickness
, b
372 def __init__(self
, possize
, pattern
= Qd
.qd
.black
, color
= (0, 0, 0)):
373 Widget
.__init
__(self
, possize
)
374 self
._framepattern
= pattern
375 self
._framecolor
= color
377 def setcolor(self
, color
):
378 self
._framecolor
= color
381 def setpattern(self
, pattern
):
382 self
._framepattern
= pattern
385 def draw(self
, visRgn
= None):
387 penstate
= Qd
.GetPenState()
388 Qd
.PenPat(self
._framepattern
)
389 Qd
.RGBForeColor(self
._framecolor
)
390 Qd
.FrameRect(self
._bounds
)
391 Qd
.RGBForeColor((0, 0, 0))
392 Qd
.SetPenState(penstate
)
395 class Group(Widget
): pass
398 class HorizontalPanes(Widget
):
402 def __init__(self
, possize
, panesizes
= None, gutter
= 8):
403 ClickableWidget
.__init
__(self
, possize
)
404 self
._panesizes
= panesizes
405 self
._gutter
= gutter
411 ClickableWidget
.open(self
)
413 def setuppanes(self
):
414 panesizes
= self
._panesizes
416 if panesizes
is not None:
417 #if len(self._widgets) <> len(panesizes):
418 # raise TypeError, 'number of widgets does not match number of panes'
419 for panesize
in panesizes
:
420 if not 0 < panesize
< 1:
421 raise TypeError, 'pane sizes must be between 0 and 1, not including.'
422 total
= total
+ panesize
423 if round(total
, 4) <> 1.0:
424 raise TypeError, 'pane sizes must add up to 1'
426 step
= 1.0 / len(self
._widgets
)
428 for i
in range(len(self
._widgets
)):
429 panesizes
.append(step
)
433 for panesize
in panesizes
:
435 self
._gutters
.append(current
)
436 self
._panesizes
.append(current
, current
+ panesize
)
437 current
= current
+ panesize
438 self
.makepanebounds()
440 def getpanesizes(self
):
441 return map(lambda (fr
, to
): to
-fr
, self
._panesizes
)
443 boundstemplate
= "lambda width, height: (0, height * %s + %d, width, height * %s + %d)"
445 def makepanebounds(self
):
446 halfgutter
= self
._gutter
/ 2
447 self
._panebounds
= []
448 for i
in range(len(self
._panesizes
)):
449 panestart
, paneend
= self
._panesizes
[i
]
450 boundsstring
= self
.boundstemplate
% (`panestart`
, panestart
and halfgutter
,
451 `paneend`
, (paneend
<> 1.0) and -halfgutter
)
452 self
._panebounds
.append(eval(boundsstring
))
454 def installbounds(self
):
456 for i
in range(len(self
._widgets
)):
458 w
._possize
= self
._panebounds
[i
]
459 #if hasattr(w, "setuppanes"):
461 if hasattr(w
, "installbounds"):
464 def rollover(self
, point
, onoff
):
466 orgmouse
= point
[self
._direction
]
467 halfgutter
= self
._gutter
/ 2
468 l
, t
, r
, b
= self
._bounds
474 i
= self
.findgutter(orgmouse
, begin
, end
)
478 SetCursor(self
._direction
and 'vmover' or 'hmover')
480 def findgutter(self
, orgmouse
, begin
, end
):
481 tolerance
= max(4, self
._gutter
) / 2
482 for i
in range(len(self
._gutters
)):
483 pos
= begin
+ (end
- begin
) * self
._gutters
[i
]
484 if abs(orgmouse
- pos
) <= tolerance
:
490 def click(self
, point
, modifiers
):
492 orgmouse
= point
[self
._direction
]
493 halfgutter
= self
._gutter
/ 2
494 l
, t
, r
, b
= self
._bounds
500 i
= self
.findgutter(orgmouse
, begin
, end
)
504 pos
= orgpos
= begin
+ (end
- begin
) * self
._gutters
[i
] # init pos too, for fast click on border, bug done by Petr
506 minpos
= self
._panesizes
[i
][0]
507 maxpos
= self
._panesizes
[i
+1][1]
508 minpos
= begin
+ (end
- begin
) * minpos
+ 64
509 maxpos
= begin
+ (end
- begin
) * maxpos
- 64
510 if minpos
> orgpos
and maxpos
< orgpos
:
516 rect
= l
, orgpos
- 1, r
, orgpos
518 rect
= orgpos
- 1, t
, orgpos
, b
520 # track mouse --- XXX move to separate method?
521 Qd
.PenMode(QuickDraw
.srcXor
)
522 Qd
.PenPat(Qd
.qd
.gray
)
526 pos
= orgpos
- orgmouse
+ Evt
.GetMouse()[self
._direction
]
527 pos
= max(pos
, minpos
)
528 pos
= min(pos
, maxpos
)
531 Qd
.PenPat(Qd
.qd
.gray
)
534 rect
= l
, pos
- 1, r
, pos
536 rect
= pos
- 1, t
, pos
, b
537 Qd
.PenPat(Qd
.qd
.gray
)
544 newpos
= (pos
- begin
) / float(end
- begin
)
545 self
._gutters
[i
] = newpos
546 self
._panesizes
[i
] = self
._panesizes
[i
][0], newpos
547 self
._panesizes
[i
+1] = newpos
, self
._panesizes
[i
+1][1]
548 self
.makepanebounds()
553 class VerticalPanes(HorizontalPanes
):
556 boundstemplate
= "lambda width, height: (width * %s + %d, 0, width * %s + %d, height)"
561 def CallbackCall(callback
, mustfit
, *args
):
562 if type(callback
) == FunctionType
:
564 maxargs
= func
.func_code
.co_argcount
565 elif type(callback
) == MethodType
:
566 func
= callback
.im_func
567 maxargs
= func
.func_code
.co_argcount
- 1
569 if callable(callback
):
570 return apply(callback
, args
)
572 raise TypeError, "uncallable callback object"
574 if func
.func_defaults
:
575 minargs
= maxargs
- len(func
.func_defaults
)
578 if minargs
<= len(args
) <= maxargs
:
579 return apply(callback
, args
)
580 elif not mustfit
and minargs
== 0:
584 raise TypeError, "callback accepts wrong number of arguments: " + `
len(args
)`
586 raise TypeError, "callback accepts wrong number of arguments: 0 or " + `
len(args
)`
589 def HasBaseClass(obj
, class_
):
600 "watch" : Qd
.GetCursor(QuickDraw
.watchCursor
).data
,
601 "arrow" : Qd
.qd
.arrow
,
602 "iBeam" : Qd
.GetCursor(QuickDraw
.iBeamCursor
).data
,
603 "cross" : Qd
.GetCursor(QuickDraw
.crossCursor
).data
,
604 "plus" : Qd
.GetCursor(QuickDraw
.plusCursor
).data
,
605 "hand" : Qd
.GetCursor(468).data
,
606 "fist" : Qd
.GetCursor(469).data
,
607 "hmover" : Qd
.GetCursor(470).data
,
608 "vmover" : Qd
.GetCursor(471).data
612 Qd
.SetCursor(_cursors
[what
])