agrandissement avec maintient du bon point de référence.
[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
31 def _initTiles(self) :
32 screen = pygame.display.get_surface()
33 tileWidth = int(round(float(screen.get_width()) / self.cols))
34 tileHeight = int(round(float(screen.get_height()) / self.rows))
35
36 self.tiles = []
37 instrus = self.instruments[:]
38 for y in range(self.cols) :
39 for x in range(self.rows) :
40 upperLeftCorner = (x * tileWidth, y * tileHeight)
41 rect = pygame.Rect(upperLeftCorner, (tileWidth, tileHeight))
42 tile = InstrumentTile(instrus.pop(0), self, rect, (x,y))
43 self.add(tile, layer=BACKGROUND_LAYER)
44 self.tiles.append(tile)
45
46 def _initCursor(self) :
47 self.cursor = WarpingCursor(blinkMode=True)
48 self.add(self.cursor, layer=CURSOR_LAYER)
49
50
51 def run(self):
52 self._running = True
53 clock = pygame.time.Clock()
54 pygame.display.flip()
55 pygame.mouse.set_visible(False)
56 while self._running :
57 EventDispatcher.dispatchEvents()
58 dirty = self.draw(pygame.display.get_surface())
59 pygame.display.update(dirty)
60 clock.tick(FRAMERATE)
61
62 def stop(self) :
63 self._running = False
64 pygame.mouse.set_visible(True)
65 self.cursor._stopBlink()
66
67 @event_handler(pygame.KEYDOWN)
68 def handleKeyDown(self, event) :
69 if event.key == pygame.K_q:
70 self.stop()
71
72 #@event_handler(pygame.MOUSEMOTION)
73 @event_handler(pygame.MOUSEBUTTONDOWN)
74 def onMouseMove(self, event) :
75 for tile in reversed(self.sprites()[:-1]) :
76 if tile.rect.collidepoint(*event.pos) :
77 self.raiseTileOver(tile)
78 break
79
80 def raiseTileOver(self, tile) :
81 self.change_layer(tile, FOREGROUND_LAYER)
82 tile.inflate(tile.coords)
83
84
85
86 class InstrumentTile(pygame.sprite.DirtySprite) :
87
88 @staticmethod
89 def _get_instrument_image(name) :
90 imagePath = os.path.abspath(__file__).split(os.path.sep)[:-1]
91 imagePath.extend(['data', 'instruments'])
92 name, ext = os.path.splitext(name)
93 imagePath.append('%s%s' % (name, ext or '.jpg'))
94 return os.path.sep.join(imagePath)
95
96 BORDER = 10
97 INFLATE_ZOOM = 0.25
98
99 def __init__(self, name, group, rect, coords) :
100 pygame.sprite.DirtySprite.__init__(self, group)
101 self.name = name
102 self.rect = rect
103 self.coords = coords
104
105
106 innerWidth, innerHeight = [l-self.BORDER*2 for l in self.rect.size]
107
108 imagePath = InstrumentTile._get_instrument_image(name)
109 img = pygame.image.load(imagePath)
110 iWidth, iHeight = img.get_size()
111 imgRatio = float(iWidth) / iHeight
112
113 # adapts dimensions
114 iw = innerWidth
115 ih = int(round(innerWidth / imgRatio))
116
117 if ih > innerHeight:
118 ih = innerHeight
119 iw = int(round(innerHeight * imgRatio))
120
121 position = ((innerWidth - iw) / 2 + self.BORDER, (innerHeight - ih) / 2 + self.BORDER)
122
123 img = pygame.transform.smoothscale(img, (iw, ih))
124
125 bg = pygame.Surface(self.rect.size)
126 bg.fill((255,255,255,255))
127 bg.blit(img, pygame.Rect(position, (iw, ih)))
128
129 self.image = bg
130
131 def inflate(self, refPoint) :
132 keep = {}
133 for name in REF_POINTS[refPoint] :
134 keep[name] = getattr(self.rect, name)
135
136 self.rect.inflate_ip(*[l*self.INFLATE_ZOOM for l in self.rect.size])
137
138 img = pygame.transform.smoothscale(self.image, self.rect.size)
139 self.image = img
140
141 for k, v in keep.items() :
142 setattr(self.rect, k, v)
143
144 self.dirty = 1
145
146
147
148 REF_POINTS = {
149 (0, 0) : ['top', 'left'],
150 (1, 0) : ['top'],
151 (2, 0) : ['top', 'right'],
152
153 (0, 1) : ['left'],
154 (1, 1) : [],
155 (2, 1) : ['right'],
156
157 (0, 2) : ['bottom', 'left'],
158 (1, 2) : ['bottom'],
159 (2, 2) : ['bottom', 'right']
160 }