Écran de sélection des instruments beaucoup plus beau.
[minwii.git] / src / app / widgets / instrumentselector.py
1 # -*- coding: utf-8 -*-
2 """
3 Écran de sélection de l'instrument
4
5 $Id$
6 $URL$
7 """
8 import os.path
9 import pygame
10 from eventutils import event_handler, EventDispatcher, EventHandlerMixin
11 from cursors import WarpingCursor
12 from config import FRAMERATE
13 from globals import BACKGROUND_LAYER
14 from globals import FOREGROUND_LAYER
15 from globals import CURSOR_LAYER
16 from globals import hls_to_rgba_8bits
17
18
19 class InstrumentSelector(pygame.sprite.LayeredDirty, EventHandlerMixin) :
20
21 rows = 3
22 cols = 3
23 instruments = ['accordeon', 'celesta', 'flute', 'guitare', 'orgue', 'piano', 'tuba', 'violon', 'violoncelle']
24
25 def __init__(self) :
26 super(InstrumentSelector, self).__init__()
27 #self._initRects()
28 self._initTiles()
29 self._initCursor()
30 self._inflatedTile = None
31
32 def _initTiles(self) :
33 screen = pygame.display.get_surface()
34 tileWidth = int(round(float(screen.get_width()) / self.cols))
35 tileHeight = int(round(float(screen.get_height()) / self.rows))
36
37 self.tiles = []
38 instrus = self.instruments[:]
39 for y in range(self.cols) :
40 for x in range(self.rows) :
41 upperLeftCorner = (x * tileWidth, y * tileHeight)
42 rect = pygame.Rect(upperLeftCorner, (tileWidth, tileHeight))
43 tile = InstrumentTile(instrus.pop(0), self, rect, (x,y))
44 self.add(tile, layer=BACKGROUND_LAYER)
45 self.tiles.append(tile)
46
47 def _initCursor(self) :
48 self.cursor = WarpingCursor(blinkMode=True)
49 self.add(self.cursor, layer=CURSOR_LAYER)
50
51
52 def run(self):
53 self._running = True
54 clock = pygame.time.Clock()
55 pygame.display.flip()
56 pygame.mouse.set_visible(False)
57 while self._running :
58 EventDispatcher.dispatchEvents()
59 dirty = self.draw(pygame.display.get_surface())
60 pygame.display.update(dirty)
61 clock.tick(FRAMERATE)
62
63 def stop(self) :
64 self._running = False
65 pygame.mouse.set_visible(True)
66 self.cursor._stopBlink()
67
68 @event_handler(pygame.KEYDOWN)
69 def handleKeyDown(self, event) :
70 if event.key == pygame.K_q:
71 self.stop()
72
73 @event_handler(pygame.MOUSEMOTION)
74 #@event_handler(pygame.MOUSEBUTTONDOWN)
75 def onMouseMove(self, event) :
76 for tile in reversed(self.sprites()[:-1]) :
77 if tile.rect.collidepoint(*event.pos) :
78 self.raiseTileOver(tile)
79 break
80
81 def raiseTileOver(self, tile) :
82 if not tile.inflated :
83 self.change_layer(tile, FOREGROUND_LAYER)
84 tile.inflate(tile.coords)
85
86 if self._inflatedTile :
87 self._inflatedTile.deflate()
88 self.change_layer(self._inflatedTile, BACKGROUND_LAYER)
89
90 self._inflatedTile = tile
91
92
93
94
95 class InstrumentTile(pygame.sprite.DirtySprite) :
96
97 @staticmethod
98 def _get_instrument_image(name) :
99 imagePath = os.path.abspath(__file__).split(os.path.sep)[:-1]
100 imagePath.extend(['data', 'instruments'])
101 name, ext = os.path.splitext(name)
102 imagePath.append('%s%s' % (name, ext or '.jpg'))
103 return os.path.sep.join(imagePath)
104
105 BORDER = 10
106 INFLATE_ZOOM = 0.4
107
108 def __init__(self, name, group, rect, coords) :
109 pygame.sprite.DirtySprite.__init__(self, group)
110 self.inflated = False
111 self.name = name
112 self.rect = rect
113 self._baseRect = rect.copy()
114 self.coords = coords
115 imagePath = InstrumentTile._get_instrument_image(name)
116 self._img = pygame.image.load(imagePath)
117 self.update()
118
119
120 def update(self) :
121 innerWidth, innerHeight = [l-self.BORDER*2 for l in self.rect.size]
122 innerSize = innerWidth, innerHeight
123
124 border = pygame.Surface(self.rect.size)
125 border.fill((0,0,0,255))
126
127 bg = pygame.Surface(innerSize)
128 bg.fill((255,255,255,255))
129 bgRect = pygame.Rect((self.BORDER, self.BORDER), innerSize)
130
131 img = self._img
132 iWidth, iHeight = img.get_size()
133 imgRatio = float(iWidth) / iHeight
134
135 # adapts dimensions
136 iw = innerWidth
137 ih = int(round(innerWidth / imgRatio))
138
139 if ih > innerHeight:
140 ih = innerHeight
141 iw = int(round(innerHeight * imgRatio))
142
143 imgPosition = ((innerWidth - iw) / 2, (innerHeight - ih) / 2)
144 imgRect = pygame.Rect(imgPosition, (iw, ih))
145 img = pygame.transform.smoothscale(img, (iw, ih))
146
147 bg.blit(img, imgRect)
148 border.blit(bg, bgRect)
149 self.image = border
150
151
152 def inflate(self, refPoint) :
153 self.inflated = True
154 keep = {}
155 for name in REF_POINTS[refPoint] :
156 keep[name] = getattr(self.rect, name)
157
158 self.rect.inflate_ip(*[l*self.INFLATE_ZOOM for l in self.rect.size])
159
160 for k, v in keep.items() :
161 setattr(self.rect, k, v)
162
163 self.update()
164 self.dirty = 1
165
166
167 def deflate(self) :
168 self.inflated = False
169 self.rect = self._baseRect.copy()
170 self.update()
171 self.dirty = 1
172
173
174
175 REF_POINTS = {
176 (0, 0) : ['top', 'left'],
177 (1, 0) : ['top'],
178 (2, 0) : ['top', 'right'],
179
180 (0, 1) : ['left'],
181 (1, 1) : [],
182 (2, 1) : ['right'],
183
184 (0, 2) : ['bottom', 'left'],
185 (1, 2) : ['bottom'],
186 (2, 2) : ['bottom', 'right']
187 }