1 # -*- coding: utf-8 -*-
4 bandes arc-en-ciel représentant un clavier.
10 from colorsys
import hls_to_rgb
11 from gradients
import gradients
12 from cursors
import WarpingCursor
13 from math
import floor
15 # TODO : positionner cette constance en fonction de la résolution d'affichage
16 # externaliser la conf.
21 ON_TOP_LUMINANCE
= 0.6
22 ON_BOTTOM_LUMINANCE
= 0.9
24 ON_COLUMN_OVERSIZING
= 1.5
27 def event_handler(eventType
) :
29 m
.__name
__ = 'eventHandler%s' % eventType
34 class MetaRenamer(type):
35 def __new__(mcs
, name
, bases
, dict) :
36 for k
, v
in dict.items() :
37 if isinstance(v
, types
.FunctionType
) :
39 print 'renommage de %s en %s' % (k
, v
.__name
__)
42 return type.__new
__(mcs
, name
, bases
, dict)
45 class _PlayingScreenBase(pygame
.sprite
.OrderedUpdates
) :
47 __metaclass__
= MetaRenamer
49 def __init__(self
, distinctNotes
=[]) :
51 distinctNotes : notes disctinctes présentes dans la chanson
52 triées du plus grave au plus aigu.
54 super(_PlayingScreenBase
, self
).__init
__()
55 self
.distinctNotes
= distinctNotes
56 self
.keyboardLength
= 0
57 self
.keyboardRects
= []
62 self
.draw(pygame
.display
.get_surface())
67 def _initRects(self
) :
68 """ création des espaces réservés pour
69 afficher les colonnes.
71 ambitus
= self
.distinctNotes
[-1].midi
- self
.distinctNotes
[0].midi
73 self
.keyboardLength
= 8
75 self
.keyboardLength
= 11
77 screen
= pygame
.display
.get_surface()
79 # taille de la zone d'affichage utile (bordure autour)
80 dispWidth
= screen
.get_width() - 2 * BORDER
81 dispHeight
= screen
.get_height() - 2 * BORDER
83 columnWidth
= int(round(float(dispWidth
) / self
.keyboardLength
))
86 for i
in range(self
.keyboardLength
) :
87 upperLeftCorner
= (i
*columnWidth
+ BORDER
, BORDER
)
88 rect
= pygame
.Rect(upperLeftCorner
, (columnWidth
, dispHeight
))
91 self
.keyboardRects
= rects
93 def _initColumns(self
) :
95 hueStep
= FIRST_HUE
/ (self
.keyboardLength
- 1)
96 for i
, rect
in enumerate(self
.keyboardRects
) :
97 hue
= FIRST_HUE
- hueStep
* i
102 def _initCursor(self
) :
103 self
.cursor
= WarpingCursor()
104 #self.add(self.cursor)
107 def highlightColumn(self
, index
) :
108 for i
, sprite
in enumerate(self
.sprites()) :
109 sprite
.update(i
==index
)
110 self
.draw(pygame
.display
.get_surface())
114 while self
._running
:
115 pygame
.display
.flip()
116 events
= pygame
.event
.get()
120 def input(self
, event
) :
121 handler
= getattr(self
, 'eventHandler%s' % event
.type, lambda e
:None)
124 @event_handler(pygame
.KEYDOWN
)
125 def handleKeyDown(self
, event
) :
126 if event
.key
== pygame
.K_q
:
127 self
._running
= False
130 if uni
.isdigit() and int(uni
) <=8 :
131 self
.highlightColumn(int(uni
))
133 @event_handler(pygame
.MOUSEMOTION
)
134 def handleMouseMotion(self
, event
) :
140 class SongPlayingScreen(_PlayingScreenBase
) :
142 def __init__(self
, song
) :
143 super(SongPlayingScreen
, self
).__init
__(song
.distinctNotes
)
146 class SongPlayingScreenTest(_PlayingScreenBase
) :
151 super(SongPlayingScreenTest
, self
).__init
__([o
])
154 class Column(pygame
.sprite
.Sprite
) :
156 def __init__(self
, hue
, rect
) :
157 pygame
.sprite
.Sprite
.__init
__(self
)
158 sur
= pygame
.surface
.Surface(rect
.size
)
159 rgba
= hls_to_rgba_8bits(hue
, OFF_LUMINANCE
, OFF_SATURATION
)
164 topRgba
= hls_to_rgba_8bits(hue
, ON_TOP_LUMINANCE
, ON_SATURATION
)
165 bottomRgba
= hls_to_rgba_8bits(hue
, ON_BOTTOM_LUMINANCE
, ON_SATURATION
)
166 rectOn
= rect
.inflate(ON_COLUMN_OVERSIZING
* rect
.width
, 0)
167 self
.stateOn
= gradients
.vertical(rectOn
.size
, topRgba
, bottomRgba
)
170 self
.image
= self
.stateOff
173 def update(self
, state
) :
175 self
.image
= self
.stateOn
176 self
.rect
= self
.rectOn
178 self
.image
= self
.stateOff
179 self
.rect
= self
.rectOff
181 def hls_to_rgba_8bits(h
, l
, s
) :
182 #convert to rgb ranging from 0 to 255
183 rgba
= [floor(255 * i
) for i
in hls_to_rgb(h
, l
, s
) + (1,)]