]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/throbber.py
2 A throbber displays an animated image that can be
3 started, stopped, reversed, etc. Useful for showing
4 an ongoing process (like most web browsers use) or
5 simply for adding eye-candy to an application.
7 Throbbers utilize a wxTimer so that normal processing
8 can continue unencumbered.
12 # throbber.py - Cliff Wells <clifford.wells@comcast.net>
14 # Thanks to Harald Massa <harald.massa@suedvers.de> for
15 # suggestions and sample code.
19 # 12/12/2003 - Jeff Grimmett (grimmtooth@softhome.net)
21 # o 2.5 compatability update.
28 # ------------------------------------------------------------------------------
30 THROBBER_EVENT
= wx
.NewEventType()
31 EVT_UPDATE_THROBBER
= wx
.PyEventBinder(THROBBER_EVENT
, 0)
33 class UpdateThrobberEvent(wx
.PyEvent
):
35 wx
.PyEvent
.__init
__(self
)
36 self
.SetEventType(THROBBER_EVENT
)
38 # ------------------------------------------------------------------------------
40 class Throbber(wx
.PyPanel
):
42 The first argument is either the name of a file that will be split into frames
43 (a composite image) or a list of strings of image names that will be treated
44 as individual frames. If a single (composite) image is given, then additional
45 information must be provided: the number of frames in the image and the width
46 of each frame. The first frame is treated as the "at rest" frame (it is not
47 shown during animation, but only when Throbber.Rest() is called.
48 A second, single image may be optionally specified to overlay on top of the
49 animation. A label may also be specified to show on top of the animation.
51 def __init__(self
, parent
, id,
52 bitmap
, # single (composite) bitmap or list of bitmaps
53 pos
= wx
.DefaultPosition
,
54 size
= wx
.DefaultSize
,
55 frameDelay
= 0.1,# time between frames
56 frames
= 0, # number of frames (only necessary for composite image)
57 frameWidth
= 0, # width of each frame (only necessary for composite image)
58 label
= None, # optional text to be displayed
59 overlay
= None, # optional image to overlay on animation
60 reverse
= 0, # reverse direction at end of animation
61 style
= 0, # window style
68 wx
.PyPanel
.__init
__(self
, parent
, id, pos
, size
, style
, name
)
71 self
.running
= (1 != 1)
72 _seqTypes
= (type([]), type(()))
74 # set size, guessing if necessary
77 if type(bitmap
) in _seqTypes
:
78 width
= bitmap
[0].GetWidth()
83 if type(bitmap
) in _seqTypes
:
84 height
= bitmap
[0].GetHeight()
86 height
= bitmap
.GetHeight()
87 self
.width
, self
.height
= width
, height
90 assert width
!= -1 and height
!= -1, "Unable to guess size"
93 extentX
, extentY
= self
.GetTextExtent(label
)
94 self
.labelX
= (width
- extentX
)/2
95 self
.labelY
= (height
- extentY
)/2
96 self
.frameDelay
= frameDelay
98 self
.current
= current
99 self
.direction
= direction
100 self
.autoReverse
= reverse
101 self
.overlay
= overlay
102 if overlay
is not None:
103 self
.overlay
= overlay
104 self
.overlayX
= (width
- self
.overlay
.GetWidth()) / 2
105 self
.overlayY
= (height
- self
.overlay
.GetHeight()) / 2
106 self
.showOverlay
= overlay
is not None
107 self
.showLabel
= label
is not None
109 # do we have a sequence of images?
110 if type(bitmap
) in _seqTypes
:
111 self
.submaps
= bitmap
112 self
.frames
= len(self
.submaps
)
113 # or a composite image that needs to be split?
117 for chunk
in range(frames
):
118 rect
= (chunk
* frameWidth
, 0, width
, height
)
119 self
.submaps
.append(bitmap
.GetSubBitmap(rect
))
121 # self.sequence can be changed, but it's not recommended doing it
122 # while the throbber is running. self.sequence[0] should always
123 # refer to whatever frame is to be shown when 'resting' and be sure
124 # that no item in self.sequence >= self.frames or < 0!!!
125 self
.SetSequence(sequence
)
127 self
.SetClientSize((width
, height
))
130 self
.timer
= wx
.Timer(self
, timerID
)
132 self
.Bind(EVT_UPDATE_THROBBER
, self
.Update
)
133 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
134 self
.Bind(wx
.EVT_TIMER
, self
.OnTimer
, self
.timer
)
135 self
.Bind(wx
.EVT_WINDOW_DESTROY
, self
.OnDestroyWindow
)
138 def DoGetBestSize(self
):
139 return (self
.width
, self
.height
)
142 def OnTimer(self
, event
):
143 wx
.PostEvent(self
, UpdateThrobberEvent())
146 def OnDestroyWindow(self
, event
):
152 dc
.DrawBitmap(self
.submaps
[self
.sequence
[self
.current
]], 0, 0, True)
153 if self
.overlay
and self
.showOverlay
:
154 dc
.DrawBitmap(self
.overlay
, self
.overlayX
, self
.overlayY
, True)
155 if self
.label
and self
.showLabel
:
156 dc
.DrawText(self
.label
, self
.labelX
, self
.labelY
)
157 dc
.SetTextForeground(wx
.WHITE
)
158 dc
.DrawText(self
.label
, self
.labelX
-1, self
.labelY
-1)
161 def OnPaint(self
, event
):
162 self
.Draw(wx
.PaintDC(self
))
166 def Update(self
, event
):
171 if self
.current
>= len(self
.sequence
):
174 self
.current
= len(self
.sequence
) - 1
182 self
.current
= len(self
.sequence
) - 1
183 self
.Draw(wx
.ClientDC(self
))
186 # --------- public methods ---------
187 def SetFont(self
, font
):
188 """Set the font for the label"""
189 wx
.Panel
.SetFont(self
, font
)
190 self
.SetLabel(self
.label
)
191 self
.Draw(wx
.ClientDC(self
))
195 """Stop the animation and return to frame 0"""
197 self
.current
= self
.rest
198 self
.Draw(wx
.ClientDC(self
))
202 """Change the direction of the animation"""
203 self
.direction
= -self
.direction
207 """Returns True if the animation is running"""
212 """Start the animation"""
214 self
.running
= not self
.running
215 self
.timer
.Start(int(self
.frameDelay
* 1000))
219 """Stop the animation"""
222 self
.running
= not self
.running
225 def SetCurrent(self
, current
):
226 """Set current image"""
227 running
= self
.Running()
229 #FIXME: need to make sure value is within range!!!
230 self
.current
= current
231 self
.Draw(wx
.ClientDC(self
))
234 def SetRest(self
, rest
):
239 def SetSequence(self
, sequence
= None):
240 """Order to display images"""
242 # self.sequence can be changed, but it's not recommended doing it
243 # while the throbber is running. self.sequence[0] should always
244 # refer to whatever frame is to be shown when 'resting' and be sure
245 # that no item in self.sequence >= self.frames or < 0!!!
247 running
= self
.Running()
250 if sequence
is not None:
251 #FIXME: need to make sure values are within range!!!
252 self
.sequence
= sequence
254 self
.sequence
= range(self
.frames
)
261 """Display next image in sequence"""
267 """Display previous image in sequence"""
273 """Display next image in sequence according to direction"""
274 self
.current
+= self
.direction
279 """Display previous image in sequence according to direction"""
280 self
.current
-= self
.direction
284 def SetFrameDelay(self
, frameDelay
= 0.05):
285 """Delay between each frame"""
286 self
.frameDelay
= frameDelay
292 def ToggleOverlay(self
, state
= None):
293 """Toggle the overlay image"""
295 self
.showOverlay
= not self
.showOverlay
297 self
.showOverlay
= state
298 self
.Draw(wx
.ClientDC(self
))
301 def ToggleLabel(self
, state
= None):
302 """Toggle the label"""
304 self
.showLabel
= not self
.showLabel
306 self
.showLabel
= state
307 self
.Draw(wx
.ClientDC(self
))
310 def SetLabel(self
, label
):
311 """Change the text of the label"""
314 extentX
, extentY
= self
.GetTextExtent(label
)
315 self
.labelX
= (self
.width
- extentX
)/2
316 self
.labelY
= (self
.height
- extentY
)/2
317 self
.Draw(wx
.ClientDC(self
))
321 # ------------------------------------------------------------------------------