Title: Graphical Cursor ClassAuthor: Frank Raiser (crashchaos at gmx.net) and Pete Shinners (pete at shinners.org) Description: This class replaces the standard cursor with a new version that gets its appearance from any surface (such as one returned by image.load()). The graphical cursor responds to mousemotion events just like the normal cursor. Download: gfxcursor.py pygame version required: Any Comments: The example script included with this class is pretty neat - it allows you to draw as in a paint program, over a multi-coloured background. Note that the graphical cursor (a simple green circle in this case) reverts to the standard pygame cursor whenever drawing is taking place. The idea of using a software-generated artificial cursor, rather than pygame's standard cursor, is an especially good one if you're considering using hardware acceleration (pygame.HWSURFACE) - the standard cursor may flicker or disappear altogether on a hardware surface. It would be pretty trivial to subclass gfxcursor to make an animated cursor - just create an "animate()" method, and call that from update(). Also note that the cursor's constructor function takes a simple surface as an argument, so the image could be generated with pygame.draw functions as it is here, loaded from an image file, or even created with pygame.font. |
""" This is a nice little GfxCursor class that gives you arbitrary mousecursor loadable from all SDL_image supported filetypes. Author: Raiser, Frank aka CrashChaos (crashchaos at gmx.net) Author: Shinners, Pete aka ShredWheat Version: 2001-12-15 Usage: Instantiate the GfxCursor class. Either pass the correct parameters to the constructor or use setCursor, setHotspot and enable lateron. The blitting is pretty optimized, the testing code at the bottom of this script does a pretty thorough test of all the drawing cases. It enables and disables the cursor, as well as uses a changing background. In your mainloop, the cursor.show() should be what you draw last (unless you want objects on top of the cursor?). Then before drawing anything, be sure to call the hide(). You can likely call hide() immediately after the display.flip() or display.update(). The show() method also returns a list of rectangles of what needs to be updated. You can also move the cursor with pygame.mouse.set_pos() That's it. Have fun with your new funky cursors. """ import pygame class GfxCursor: """ Replaces the normal pygame cursor with any bitmap cursor """ def __init__(self,surface,cursor=None,hotspot=(0,0)): """ surface = Global surface to draw on cursor = surface of cursor (needs to be specified when enabled!) hotspot = the hotspot for your cursor """ self.surface = surface self.enabled = 0 self.cursor = None self.hotspot = hotspot self.bg = None self.offset = 0,0 self.old_pos = 0,0 if cursor: self.setCursor(cursor,hotspot) self.enable() def enable(self): """ Enable the GfxCursor (disable normal pygame cursor) """ if not self.cursor or self.enabled: return pygame.mouse.set_visible(0) self.enabled = 1 def disable(self): """ Disable the GfxCursor (enable normal pygame cursor) """ if self.enabled: self.hide() pygame.mouse.set_visible(1) self.enabled = 0 def setCursor(self,cursor,hotspot=(0,0)): """ Set a new cursor surface """ if not cursor: return self.cursor = cursor self.hide() self.show() self.offset = 0,0 self.bg = pygame.Surface(self.cursor.get_size()) pos = self.old_pos[0]-self.offset[0],self.old_pos[1]-self.offset[1] self.bg.blit(self.surface,(0,0), (pos[0],pos[1],self.cursor.get_width(),self.cursor.get_height())) self.offset = hotspot def setHotspot(self,pos): """ Set a new hotspot for the cursor """ self.hide() self.offset = pos def hide(self): """ Hide the cursor (useful for redraws) """ if self.bg and self.enabled: return self.surface.blit(self.bg, (self.old_pos[0]-self.offset[0],self.old_pos[1]-self.offset[1])) def show(self): """ Show the cursor again """ if self.bg and self.enabled: pos = self.old_pos[0]-self.offset[0],self.old_pos[1]-self.offset[1] self.bg.blit(self.surface,(0,0), (pos[0],pos[1],self.cursor.get_width(),self.cursor.get_height())) return self.surface.blit(self.cursor,pos) def update(self,event): """ Update the cursor with a MOUSEMOTION event """ self.old_pos = event.pos if __name__ == '__main__': #test it out import pygame.draw pygame.init() screen = pygame.display.set_mode((400, 300)) screen.fill((50, 50, 111), (0, 0, 400, 150)) pygame.display.flip() pygame.display.set_caption('Test the GfxCursor (and paint)') image = pygame.Surface((20, 20)) pygame.draw.circle(image, (50, 220, 100), (10, 10), 8, 0) pygame.draw.circle(image, (220, 200, 50), (10, 10), 8, 2) image.set_at((9, 9), (255,255,255)) image.set_colorkey(0, pygame.RLEACCEL) magicbox = pygame.Rect(10, 10, 100, 90) magiccolor = 0 cursor = GfxCursor(screen, image, (10, 10)) finished = 0 downpos = None while not finished: dirtyrects = [] dirtyrects.extend([cursor.hide()]) for e in pygame.event.get(): if e.type in (pygame.QUIT, pygame.KEYDOWN): finished = 1 break elif e.type == pygame.MOUSEBUTTONDOWN: cursor.disable() downpos = e.pos elif e.type == pygame.MOUSEBUTTONUP: cursor.enable() downpos = None elif downpos and e.type == pygame.MOUSEMOTION: r = pygame.draw.line(screen, (100,100,100), downpos, e.pos, 2) dirtyrects.append(r) downpos = e.pos cursor.update(e) elif not downpos and e.type == pygame.MOUSEMOTION: cursor.update(e) magiccolor = (magiccolor + 2) % 255 r = screen.fill((0, 0, magiccolor), magicbox) dirtyrects.append(r) #here's how we sandwich the flip/update with cursor show and hide dirtyrects.extend([cursor.show()]) pygame.display.update(dirtyrects) pygame.time.delay(5) #should be time.wait(5) with pygame-1.3 :]
Main - Repository - Submit - News |