demo to match. Also fixed some deprecation warnings. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27049 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			255 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| A throbber displays an animated image that can be
 | |
| started, stopped, reversed, etc.  Useful for showing
 | |
| an ongoing process (like most web browsers use) or
 | |
| simply for adding eye-candy to an application.
 | |
| 
 | |
| Throbbers utilize a wxTimer so that normal processing
 | |
| can continue unencumbered.
 | |
| """
 | |
| 
 | |
| #
 | |
| # throbber.py - Cliff Wells <clifford.wells@comcast.net>
 | |
| #
 | |
| # Thanks to Harald Massa <harald.massa@suedvers.de> for
 | |
| # suggestions and sample code.
 | |
| #
 | |
| # $Id$
 | |
| #
 | |
| # 12/12/2003 - Jeff Grimmett (grimmtooth@softhome.net)
 | |
| #
 | |
| # o 2.5 compatability update.
 | |
| #
 | |
| 
 | |
| 
 | |
| import os
 | |
| import wx
 | |
| 
 | |
| # ------------------------------------------------------------------------------
 | |
| 
 | |
| THROBBER_EVENT = wx.NewEventType()
 | |
| EVT_UPDATE_THROBBER = wx.PyEventBinder(THROBBER_EVENT, 0)
 | |
| 
 | |
| class UpdateThrobberEvent(wx.PyEvent):
 | |
|     def __init__(self):
 | |
|         wx.PyEvent.__init__(self)
 | |
|         self.SetEventType(THROBBER_EVENT)
 | |
| 
 | |
| # ------------------------------------------------------------------------------
 | |
| 
 | |
| class Throbber(wx.PyPanel):
 | |
|     """
 | |
|     The first argument is either the name of a file that will be split into frames
 | |
|     (a composite image) or a list of  strings of image names that will be treated
 | |
|     as individual frames.  If a single (composite) image is given, then additional
 | |
|     information must be provided: the number of frames in the image and the width
 | |
|     of each frame.  The first frame is treated as the "at rest" frame (it is not
 | |
|     shown during animation, but only when Throbber.Rest() is called.
 | |
|     A second, single image may be optionally specified to overlay on top of the
 | |
|     animation. A label may also be specified to show on top of the animation.
 | |
|     """
 | |
|     def __init__(self, parent, id,
 | |
|                  bitmap,          # single (composite) bitmap or list of bitmaps
 | |
|                  pos = wx.DefaultPosition,
 | |
|                  size = wx.DefaultSize,
 | |
|                  frameDelay = 0.1,# time between frames
 | |
|                  frames = 0,      # number of frames (only necessary for composite image)
 | |
|                  frameWidth = 0,  # width of each frame (only necessary for composite image)
 | |
|                  label = None,    # optional text to be displayed
 | |
|                  overlay = None,  # optional image to overlay on animation
 | |
|                  reverse = 0,     # reverse direction at end of animation
 | |
|                  style = 0,       # window style
 | |
|                  name = "throbber"):
 | |
|         wx.PyPanel.__init__(self, parent, id, pos, size, style, name)
 | |
|         self.name = name
 | |
|         self.label = label
 | |
|         self.running = (1 != 1)
 | |
|         _seqTypes = (type([]), type(()))
 | |
| 
 | |
|         # set size, guessing if necessary
 | |
|         width, height = size
 | |
|         if width == -1:
 | |
|             if type(bitmap) in _seqTypes:
 | |
|                 width = bitmap[0].GetWidth()
 | |
|             else:
 | |
|                 if frameWidth:
 | |
|                     width = frameWidth
 | |
|         if height == -1:
 | |
|             if type(bitmap) in _seqTypes:
 | |
|                 height = bitmap[0].GetHeight()
 | |
|             else:
 | |
|                 height = bitmap.GetHeight()
 | |
|         self.width, self.height = width, height
 | |
| 
 | |
|         # double check it
 | |
|         assert width != -1 and height != -1, "Unable to guess size"
 | |
| 
 | |
|         if label:
 | |
|             extentX, extentY = self.GetTextExtent(label)
 | |
|             self.labelX = (width - extentX)/2
 | |
|             self.labelY = (height - extentY)/2
 | |
|         self.frameDelay = frameDelay
 | |
|         self.current = 0
 | |
|         self.direction = 1
 | |
|         self.autoReverse = reverse
 | |
|         self.overlay = overlay
 | |
|         if overlay is not None:
 | |
|             self.overlay = overlay
 | |
|             self.overlayX = (width - self.overlay.GetWidth()) / 2
 | |
|             self.overlayY = (height - self.overlay.GetHeight()) / 2
 | |
|         self.showOverlay = overlay is not None
 | |
|         self.showLabel = label is not None
 | |
| 
 | |
|         # do we have a sequence of images?
 | |
|         if type(bitmap) in _seqTypes:
 | |
|             self.submaps = bitmap
 | |
|             self.frames = len(self.submaps)
 | |
|         # or a composite image that needs to be split?
 | |
|         else:
 | |
|             self.frames = frames
 | |
|             self.submaps = []
 | |
|             for chunk in range(frames):
 | |
|                 rect = (chunk * frameWidth, 0, width, height)
 | |
|                 self.submaps.append(bitmap.GetSubBitmap(rect))
 | |
| 
 | |
|         # self.sequence can be changed, but it's not recommended doing it
 | |
|         # while the throbber is running.  self.sequence[0] should always
 | |
|         # refer to whatever frame is to be shown when 'resting' and be sure
 | |
|         # that no item in self.sequence >= self.frames or < 0!!!
 | |
|         self.sequence = range(self.frames)
 | |
| 
 | |
|         self.SetClientSize((width, height))
 | |
| 
 | |
|         timerID  = wx.NewId()
 | |
|         self.timer = wx.Timer(self, timerID)
 | |
| 
 | |
|         self.Bind(EVT_UPDATE_THROBBER, self.Rotate)
 | |
|         self.Bind(wx.EVT_PAINT, self.OnPaint)
 | |
|         self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
 | |
|         self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroyWindow)
 | |
| 
 | |
| 
 | |
|     def DoGetBestSize(self):
 | |
|         return (self.width, self.height)
 | |
|     
 | |
| 
 | |
|     def OnTimer(self, event):
 | |
|         wx.PostEvent(self, UpdateThrobberEvent())
 | |
| 
 | |
| 
 | |
|     def OnDestroyWindow(self, event):
 | |
|         self.Stop()
 | |
|         event.Skip()
 | |
| 
 | |
| 
 | |
|     def Draw(self, dc):
 | |
|         dc.DrawBitmap(self.submaps[self.sequence[self.current]], 0, 0, True)
 | |
|         if self.overlay and self.showOverlay:
 | |
|             dc.DrawBitmap(self.overlay, self.overlayX, self.overlayY, True)
 | |
|         if self.label and self.showLabel:
 | |
|             dc.DrawText(self.label, self.labelX, self.labelY)
 | |
|             dc.SetTextForeground(wx.WHITE)
 | |
|             dc.DrawText(self.label, self.labelX-1, self.labelY-1)
 | |
| 
 | |
| 
 | |
|     def OnPaint(self, event):
 | |
|         self.Draw(wx.PaintDC(self))
 | |
|         event.Skip()
 | |
| 
 | |
| 
 | |
|     def Rotate(self, event):
 | |
|         self.current += self.direction
 | |
|         if self.current >= len(self.sequence):
 | |
|             if self.autoReverse:
 | |
|                 self.Reverse()
 | |
|                 self.current = len(self.sequence) - 1
 | |
|             else:
 | |
|                 self.current = 1
 | |
|         if self.current < 1:
 | |
|             if self.autoReverse:
 | |
|                 self.Reverse()
 | |
|                 self.current = 1
 | |
|             else:
 | |
|                 self.current = len(self.sequence) - 1
 | |
|         self.Draw(wx.ClientDC(self))
 | |
| 
 | |
| 
 | |
|     # --------- public methods ---------
 | |
|     def SetFont(self, font):
 | |
|         """Set the font for the label"""
 | |
|         wx.Panel.SetFont(self, font)
 | |
|         self.SetLabel(self.label)
 | |
|         self.Draw(wx.ClientDC(self))
 | |
| 
 | |
| 
 | |
|     def Rest(self):
 | |
|         """Stop the animation and return to frame 0"""
 | |
|         self.Stop()
 | |
|         self.current = 0
 | |
|         self.Draw(wx.ClientDC(self))
 | |
| 
 | |
| 
 | |
|     def Reverse(self):
 | |
|         """Change the direction of the animation"""
 | |
|         self.direction = -self.direction
 | |
| 
 | |
| 
 | |
|     def Running(self):
 | |
|         """Returns True if the animation is running"""
 | |
|         return self.running
 | |
| 
 | |
| 
 | |
|     def Start(self):
 | |
|         """Start the animation"""
 | |
|         if not self.running:
 | |
|             self.running = not self.running
 | |
|             self.timer.Start(int(self.frameDelay * 1000))
 | |
| 
 | |
| 
 | |
|     def Stop(self):
 | |
|         """Stop the animation"""
 | |
|         if self.running:
 | |
|             self.timer.Stop()
 | |
|             self.running = not self.running
 | |
| 
 | |
| 
 | |
|     def SetFrameDelay(self, frameDelay = 0.05):
 | |
|         """Delay between each frame"""
 | |
|         self.frameDelay = frameDelay
 | |
|         if self.running:
 | |
|             self.Stop()
 | |
|             self.Start()
 | |
| 
 | |
| 
 | |
|     def ToggleOverlay(self, state = None):
 | |
|         """Toggle the overlay image"""
 | |
|         if state is None:
 | |
|             self.showOverlay = not self.showOverlay
 | |
|         else:
 | |
|             self.showOverlay = state
 | |
|         self.Draw(wx.ClientDC(self))
 | |
| 
 | |
| 
 | |
|     def ToggleLabel(self, state = None):
 | |
|         """Toggle the label"""
 | |
|         if state is None:
 | |
|             self.showLabel = not self.showLabel
 | |
|         else:
 | |
|             self.showLabel = state
 | |
|         self.Draw(wx.ClientDC(self))
 | |
| 
 | |
| 
 | |
|     def SetLabel(self, label):
 | |
|         """Change the text of the label"""
 | |
|         self.label = label
 | |
|         if label:
 | |
|             extentX, extentY = self.GetTextExtent(label)
 | |
|             self.labelX = (self.width - extentX)/2
 | |
|             self.labelY = (self.height - extentY)/2
 | |
|         self.Draw(wx.ClientDC(self))
 | |
| 
 | |
| 
 | |
| 
 | |
| # ------------------------------------------------------------------------------
 | |
| 
 |