cleanup.
[minwii.git] / src / app / widgets / cursors.py
index 6729fc9..c8df104 100755 (executable)
@@ -8,107 +8,123 @@ $URL$
 
 import pygame
 import os
 
 import pygame
 import os
+from threading import Thread
+import time
+from eventutils import EventHandlerMixin, event_handler
+from itertools import cycle
 
 
-
-class WarpingCursor(pygame.sprite.Sprite):
+class WarpingCursor(pygame.sprite.DirtySprite, EventHandlerMixin):
     '''
     The class for animating the warping cursor
     '''
     The class for animating the warping cursor
-        
-        durations:
-            The duration of each image in the animation
-        centerPosition:
-            The Position of the center of the cursor
-        _imagePointer:
-            A pointer to the current image
-        _animationOffset:
-            The time elapsed since when the current image should have been displayed
     '''
     '''
-    #screen = None
-    #images = None
-    #durations = None
-    #centerPosition = None
-    #_imagePointer = None
-    #_animationOffset = None
 
     @staticmethod
 
     @staticmethod
-    def _get_theme_images(name) : 
+    def _get_theme_images(name) :
         basePath = os.path.abspath(__file__).split(os.path.sep)[:-1]
         basePath = os.path.abspath(__file__).split(os.path.sep)[:-1]
-        basePath.append('data')
+        basePath.extend(['data', 'cursor'])
         basePath.append(name)
         basePath = os.path.sep.join(basePath)
         images = [f for f in os.listdir(basePath) if os.path.splitext(f)[1] == '.png']
         return basePath, images
         basePath.append(name)
         basePath = os.path.sep.join(basePath)
         images = [f for f in os.listdir(basePath) if os.path.splitext(f)[1] == '.png']
         return basePath, images
-    
 
 
-    def __init__(self, theme='black', duration=75):
-        pygame.sprite.Sprite.__init__(self)
+    
+    def __init__(self, theme='black', duration=50, blinkMode=True):
+        pygame.sprite.DirtySprite.__init__(self)
         imagesPath, images = WarpingCursor._get_theme_images(theme)
         flashImage = images.pop(images.index('flash.png'))
         imagesPath, images = WarpingCursor._get_theme_images(theme)
         flashImage = images.pop(images.index('flash.png'))
+        flashImagePath = os.path.sep.join([imagesPath, flashImage]) 
+        self.flashImage = pygame.image.load(flashImagePath).convert_alpha()
         images.sort(lambda a, b : cmp(*[int(os.path.splitext(f)[0]) for f in [a, b]]))
         images.sort(lambda a, b : cmp(*[int(os.path.splitext(f)[0]) for f in [a, b]]))
-
+        
         self.images = []
         for img in images :
             imagePath = os.path.sep.join([imagesPath, img])
         self.images = []
         for img in images :
             imagePath = os.path.sep.join([imagesPath, img])
-            self.images = pygame.image.load(imagePath).convert_alpha()
+            img = pygame.image.load(imagePath).convert_alpha()
+            self.images.append(img)
         
         
+        # assumes that all images have same dimensions
+        self.width = self.images[0].get_width()
+        self.height = self.images[0].get_height()
         self.duration = duration
         self.duration = duration
-            
-        #self.flashImagePath = flashImage
-        #self.durations = durations
-        #self.centerPosition = initCenterPosition
-        #self.flashLength = 100
-        #self.flashing = False
-        #self.image = pygame.image.load(self.images[0]).convert_alpha()
-        #self._imagePointer = 0
-        #self._animationOffset = 0
-        #self._flashTimer = 0        
-    
-    def update(self, elapsedTime, centerPosition):
-        '''
-        Update the cursor's look and position
-        
-            elapsedTime:
-                The time passed since the previous update
-            centerPosition:
-                the new position of the creep
-        '''
-        self._updateImage(elapsedTime)
-        self.centerPosition = centerPosition
-        if self.flashing :
-            self._flashTimer += elapsedTime
-            if self._flashTimer > self.flashLength:
-                self.flashing = False
-    
-    def _updateImage(self, elapsedTime):
-        '''
-        Update the cursor's image
         
         
-            elapsedTime:
-                The time passed since the previous update
-        '''
-        self._animationOffset += elapsedTime
+        self.image = self.images[0]
+        # workarround cursor alignement problem
+        pygame.event.set_blocked(pygame.MOUSEMOTION)
+        pygame.mouse.set_pos(pygame.mouse.get_pos())
+        pygame.event.set_allowed(pygame.MOUSEMOTION)
+        # ---
+        x, y = pygame.mouse.get_pos()
+        left = x - self.width / 2
+        top = y - self.height / 2
+        self.rect = pygame.Rect((left, top), (self.width, self.height))
         
         
-        if self._animationOffset > self.durations[self._imagePointer]:
-            #New animation offset is computed first, before updating the pointer
-            self._animationOffset -= self.durations[self._imagePointer]
-            #point to the next image (restarts from the beginning when it reaches the end)
-            self._imagePointer = (self._imagePointer + 1) % len(self.images)
+        self.blinkMode = blinkMode
+        self._startBlink()
+    
+    def __del__(self) :
+        if hasattr(self, 'timer') :
+            try : self.timer.stop()
+            except : pass
+    
+    def _startBlink(self) :
+        if self.blinkMode :
+            self._blinking = True
+            self.iterator = self.iterImages()
+            self.timer = ForeverTimer(self.duration, self.loadNext)
+            self.timer.start()
+    
+    def _stopBlink(self) :
+        if self.blinkMode :
+            self.timer.stop()
             
             
-        if self.flashing:
-            self.image = pygame.image.load(self.flashImagePath).convert_alpha()                       
-        else :    
-            self.image = pygame.image.load(self.images[self._imagePointer]).convert_alpha()
-        
-    def flash(self,flashLength = None):
-        self._flashTimer = 0
-        self.flashing = True
-        if flashLength:
-            self.flashlength = flashLength
+    def iterImages(self) :
+        for img in cycle(self.images) :
+            yield img
     
     
-    def blit(self,surface):
-        '''
-        Draw the circle on surface
-        '''
-        
-        newPos = (self.centerPosition[0] - self.image.get_width() / 2, self.centerPosition[1] - self.image.get_height() / 2)
-        surface.blit(self.image, newPos)
+    def loadNext(self) :
+        if self._blinking :
+            self.dirty = 1
+            self.image = self.iterator.next()
+    
+    @event_handler(pygame.MOUSEBUTTONDOWN)
+    def flashOn(self, event) :
+        self.dirty = 1
+        self._blinking = False
+        self.image = self.flashImage
+
+    @event_handler(pygame.MOUSEBUTTONUP)
+    def flashOff(self, event) :
+        self.dirty = 1
+        if self.blinkMode :
+            self._blinking = True
+        else :
+            self.image = self.images[0]
+    
+    @event_handler(pygame.MOUSEMOTION)
+    def move(self, event) :
+        self.dirty = 1
+        self.rect.move_ip(event.rel)
+    
+    def setPosition(self, pos) :
+        self.dirty = 1
+        x, y = pos
+        rx, ry = self.rect.centerx, self.rect.centery
+        self.rect.move_ip(x-rx, y-ry)
+
+
+class ForeverTimer(Thread) :
+    def __init__(self, duration, func, *args, **kw) :
+        Thread.__init__(self)
+        self.duration = duration / 1000.
+        self.func = func
+        self.args = args
+        self.kw = kw
+        self.running = True
+
+    def run(self) :
+        while self.running :
+            self.func(*self.args, **self.kw)
+            time.sleep(self.duration)
+    
+    def stop(self) :
+        self.running = False
\ No newline at end of file