ad8f3834922a2c3043bde216338c55abff8aa42c
[minwii.git] / src / minwii / widgets / cursors.py
1 # -*- coding: utf-8 -*-
2 """
3 Curseurs winwii
4
5 $Id$
6 $URL$
7 """
8
9 import pygame
10 import os
11 from threading import Thread
12 import time
13 from minwii.eventutils import EventHandlerMixin, event_handler
14 from itertools import cycle
15
16 class WarpingCursor(pygame.sprite.DirtySprite, EventHandlerMixin):
17 '''
18 The class for animating the warping cursor
19 '''
20
21 @staticmethod
22 def _get_theme_images(name) :
23 basePath = os.path.abspath(__file__).split(os.path.sep)[:-1]
24 basePath.extend(['data', 'cursor'])
25 basePath.append(name)
26 basePath = os.path.sep.join(basePath)
27 images = [f for f in os.listdir(basePath) if os.path.splitext(f)[1] == '.png']
28 return basePath, images
29
30
31 def __init__(self, theme='black-perforated', duration=100, blinkMode=True):
32 pygame.sprite.DirtySprite.__init__(self)
33 imagesPath, images = WarpingCursor._get_theme_images(theme)
34 flashImage = images.pop(images.index('flash.png'))
35 flashImagePath = os.path.sep.join([imagesPath, flashImage])
36 self.flashImage = pygame.image.load(flashImagePath).convert_alpha()
37 images.sort(lambda a, b : cmp(*[int(os.path.splitext(f)[0]) for f in [a, b]]))
38
39 self.images = []
40 for img in images :
41 imagePath = os.path.sep.join([imagesPath, img])
42 img = pygame.image.load(imagePath).convert_alpha()
43 self.images.append(img)
44
45 # assumes that all images have same dimensions
46 self.width = self.images[0].get_width()
47 self.height = self.images[0].get_height()
48 self.duration = duration
49
50 self.image = self.images[0]
51 # workarround cursor alignement problem
52 pygame.event.set_blocked(pygame.MOUSEMOTION)
53 pygame.mouse.set_pos(pygame.mouse.get_pos())
54 pygame.event.set_allowed(pygame.MOUSEMOTION)
55 # ---
56 x, y = pygame.mouse.get_pos()
57 left = x - self.width / 2
58 top = y - self.height / 2
59 self.rect = pygame.Rect((left, top), (self.width, self.height))
60
61 self.blinkMode = blinkMode
62 self._startBlink()
63
64 def __del__(self) :
65 if hasattr(self, 'timer') :
66 try : self.timer.stop()
67 except : pass
68
69 def _startBlink(self) :
70 if self.blinkMode :
71 self._blinking = True
72 self.iterator = self.iterImages()
73 self.timer = ForeverTimer(self.duration, self.loadNext)
74 self.timer.start()
75
76 def _stopBlink(self) :
77 if self.blinkMode :
78 self.timer.stop()
79
80 def iterImages(self) :
81 for img in cycle(self.images) :
82 yield img
83
84 def loadNext(self) :
85 if self._blinking :
86 self.dirty = 1
87 self.image = self.iterator.next()
88
89 @event_handler(pygame.MOUSEBUTTONDOWN)
90 def flashOn(self, event) :
91 self.dirty = 1
92 self._blinking = False
93 self.image = self.flashImage
94
95 @event_handler(pygame.MOUSEBUTTONUP)
96 def flashOff(self, event) :
97 self.dirty = 1
98 if self.blinkMode :
99 self._blinking = True
100 else :
101 self.image = self.images[0]
102
103 @event_handler(pygame.MOUSEMOTION)
104 def move(self, event) :
105 self.dirty = 1
106 self.rect.move_ip(event.rel)
107
108 def setPosition(self, pos) :
109 self.dirty = 1
110 x, y = pos
111 rx, ry = self.rect.centerx, self.rect.centery
112 self.rect.move_ip(x-rx, y-ry)
113
114
115 class ForeverTimer(Thread) :
116 def __init__(self, duration, func, *args, **kw) :
117 Thread.__init__(self)
118 self.duration = duration / 1000.
119 self.func = func
120 self.args = args
121 self.kw = kw
122 self.running = True
123
124 def run(self) :
125 while self.running :
126 self.func(*self.args, **self.kw)
127 time.sleep(self.duration)
128
129 def stop(self) :
130 self.running = False