création d'un dispatcher d'événement central.
[minwii.git] / src / app / widgets / playingscreen.py
1 # -*- coding: utf-8 -*-
2 """
3 Écran de jeu MinWii :
4 bandes arc-en-ciel représentant un clavier.
5
6 $Id$
7 $URL$
8 """
9 import pygame
10 from colorsys import hls_to_rgb
11 from gradients import gradients
12 from cursors import WarpingCursor
13 from eventutils import event_handler, EventDispatcher, EventHandlerMixin
14 from math import floor
15 import types
16 # TODO : positionner cette constance en fonction de la résolution d'affichage
17 # externaliser la conf.
18 BORDER = 5 # 5px
19 FIRST_HUE = 0.6
20 OFF_LUMINANCE = 0.2
21 OFF_SATURATION = 1
22 ON_TOP_LUMINANCE = 0.6
23 ON_BOTTOM_LUMINANCE = 0.9
24 ON_SATURATION = 1
25 ON_COLUMN_OVERSIZING = 1.5
26
27
28 class _PlayingScreenBase(pygame.sprite.OrderedUpdates, EventHandlerMixin) :
29
30 def __init__(self, distinctNotes=[]) :
31 """
32 distinctNotes : notes disctinctes présentes dans la chanson
33 triées du plus grave au plus aigu.
34 """
35 print '__init__ _PlayingScreenBase'
36 super(_PlayingScreenBase, self).__init__()
37 self.distinctNotes = distinctNotes
38 self.keyboardLength = 0
39 self.keyboardRects = []
40 self.cursor = None
41 self._initRects()
42 self._initColumns()
43 self._running = False
44 self.draw(pygame.display.get_surface())
45 self._initCursor()
46
47
48
49 def _initRects(self) :
50 """ création des espaces réservés pour
51 afficher les colonnes.
52 """
53 ambitus = self.distinctNotes[-1].midi - self.distinctNotes[0].midi
54 if ambitus <= 12 :
55 self.keyboardLength = 8
56 else :
57 self.keyboardLength = 11
58
59 screen = pygame.display.get_surface()
60
61 # taille de la zone d'affichage utile (bordure autour)
62 dispWidth = screen.get_width() - 2 * BORDER
63 dispHeight = screen.get_height() - 2 * BORDER
64
65 columnWidth = int(round(float(dispWidth) / self.keyboardLength))
66
67 rects = []
68 for i in range(self.keyboardLength) :
69 upperLeftCorner = (i*columnWidth + BORDER, BORDER)
70 rect = pygame.Rect(upperLeftCorner, (columnWidth, dispHeight))
71 rects.append(rect)
72
73 self.keyboardRects = rects
74
75 def _initColumns(self) :
76
77 hueStep = FIRST_HUE / (self.keyboardLength - 1)
78 for i, rect in enumerate(self.keyboardRects) :
79 hue = FIRST_HUE - hueStep * i
80 c = Column(hue, rect)
81 self.add(c)
82
83 def _initCursor(self) :
84 self.cursor = WarpingCursor()
85 #self.add(self.cursor)
86
87
88 def highlightColumn(self, index) :
89 for i, sprite in enumerate(self.sprites()) :
90 sprite.update(i==index)
91 self.draw(pygame.display.get_surface())
92
93 def run(self):
94 self._running = True
95 clock = pygame.time.Clock()
96 while self._running :
97 pygame.display.flip()
98 EventDispatcher.dispatchEvents()
99 clock.tick(50)
100
101 @event_handler(pygame.KEYDOWN)
102 def handleKeyDown(self, event) :
103 if event.key == pygame.K_q:
104 self._running = False
105 uni = event.unicode
106
107 if uni.isdigit() and int(uni) <=8 :
108 self.highlightColumn(int(uni))
109
110 @event_handler(pygame.MOUSEMOTION)
111 def handleMouseMotion(self, event) :
112 pass
113
114
115
116
117 class SongPlayingScreen(_PlayingScreenBase) :
118
119 def __init__(self, song) :
120 super(SongPlayingScreen, self).__init__(song.distinctNotes)
121 self.song = song
122
123 class SongPlayingScreenTest(_PlayingScreenBase) :
124 def __init__(self) :
125 print '__init__ SongPlayingScreenTest'
126 class C:pass
127 o = C()
128 o.midi=1
129 super(SongPlayingScreenTest, self).__init__([o])
130
131
132 class Column(pygame.sprite.Sprite) :
133
134 def __init__(self, hue, rect) :
135 pygame.sprite.Sprite.__init__(self)
136 sur = pygame.surface.Surface(rect.size)
137 rgba = hls_to_rgba_8bits(hue, OFF_LUMINANCE, OFF_SATURATION)
138 sur.fill(rgba)
139 self.stateOff = sur
140 self.rectOff = rect
141
142 topRgba = hls_to_rgba_8bits(hue, ON_TOP_LUMINANCE, ON_SATURATION)
143 bottomRgba = hls_to_rgba_8bits(hue, ON_BOTTOM_LUMINANCE, ON_SATURATION)
144 rectOn = rect.inflate(ON_COLUMN_OVERSIZING * rect.width, 0)
145 self.stateOn = gradients.vertical(rectOn.size, topRgba, bottomRgba)
146 self.rectOn = rectOn
147
148 self.image = self.stateOff
149 self.rect = rect
150
151 def update(self, state) :
152 if state :
153 self.image = self.stateOn
154 self.rect = self.rectOn
155 else :
156 self.image = self.stateOff
157 self.rect = self.rectOff
158
159 def hls_to_rgba_8bits(h, l, s) :
160 #convert to rgb ranging from 0 to 255
161 rgba = [floor(255 * i) for i in hls_to_rgb(h, l, s) + (1,)]
162 return tuple(rgba)