Refactoring orienté objet.
[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 self.pressed = False
52 # workarround cursor alignement problem
53 pygame.event.set_blocked(pygame.MOUSEMOTION)
54 pygame.mouse.set_pos(pygame.mouse.get_pos())
55 pygame.event.set_allowed(pygame.MOUSEMOTION)
56 # ---
57 x, y = pygame.mouse.get_pos()
58 left = x - self.width / 2
59 top = y - self.height / 2
60 self.rect = pygame.Rect((left, top), (self.width, self.height))
61
62 self.blinkMode = blinkMode
63 self._startBlink()
64
65 def __del__(self) :
66 if hasattr(self, 'timer') :
67 try : self.timer.stop()
68 except : pass
69
70 def _startBlink(self) :
71 if self.blinkMode :
72 self._blinking = True
73 self.iterator = self.iterImages()
74 self.timer = ForeverTimer(self.duration, self.loadNext)
75 self.timer.start()
76
77 def _stopBlink(self) :
78 if self.blinkMode :
79 self.timer.stop()
80
81 def iterImages(self) :
82 for img in cycle(self.images) :
83 yield img
84
85 def loadNext(self) :
86 if self._blinking :
87 self.dirty = 1
88 self.image = self.iterator.next()
89
90 @event_handler(pygame.MOUSEBUTTONDOWN)
91 def flashOn(self, event) :
92 self.dirty = 1
93 self._blinking = False
94 self.image = self.flashImage
95 self.pressed = True
96
97 @event_handler(pygame.MOUSEBUTTONUP)
98 def flashOff(self, event) :
99 self.dirty = 1
100 if self.blinkMode :
101 self._blinking = True
102 else :
103 self.image = self.images[0]
104 self.pressed = False
105
106 @event_handler(pygame.MOUSEMOTION)
107 def move(self, event) :
108 self.dirty = 1
109 x, y = pygame.mouse.get_pos()
110 rel = (x - self.rect.centerx, y - self.rect.centery)
111 self.rect.move_ip(rel)
112
113 def setPosition(self, pos) :
114 self.dirty = 1
115 x, y = pos
116 rx, ry = self.rect.centerx, self.rect.centery
117 self.rect.move_ip(x-rx, y-ry)
118
119
120 class ForeverTimer(Thread) :
121 def __init__(self, duration, func, *args, **kw) :
122 Thread.__init__(self)
123 self.duration = duration / 1000.
124 self.func = func
125 self.args = args
126 self.kw = kw
127 self.running = True
128
129 def run(self) :
130 while self.running :
131 self.func(*self.args, **self.kw)
132 time.sleep(self.duration)
133
134 def stop(self) :
135 self.running = False