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 eventutils
import event_handler
, EventDispatcher
, EventHandlerMixin
14 from math
import floor
16 # TODO : positionner cette constance en fonction de la résolution d'affichage
17 # externaliser la conf.
22 ON_TOP_LUMINANCE
= 0.6
23 ON_BOTTOM_LUMINANCE
= 0.9
25 ON_COLUMN_OVERSIZING
= 1.5
28 class _PlayingScreenBase(pygame
.sprite
.OrderedUpdates
, EventHandlerMixin
) :
30 def __init__(self
, distinctNotes
=[]) :
32 distinctNotes : notes disctinctes présentes dans la chanson
33 triées du plus grave au plus aigu.
35 super(_PlayingScreenBase
, self
).__init
__()
36 self
.distinctNotes
= distinctNotes
37 self
.keyboardLength
= 0
38 self
.keyboardRects
= []
43 self
.draw(pygame
.display
.get_surface())
48 def _initRects(self
) :
49 """ création des espaces réservés pour
50 afficher les colonnes.
52 ambitus
= self
.distinctNotes
[-1].midi
- self
.distinctNotes
[0].midi
54 self
.keyboardLength
= 8
56 self
.keyboardLength
= 11
58 screen
= pygame
.display
.get_surface()
60 # taille de la zone d'affichage utile (bordure autour)
61 dispWidth
= screen
.get_width() - 2 * BORDER
62 dispHeight
= screen
.get_height() - 2 * BORDER
64 columnWidth
= int(round(float(dispWidth
) / self
.keyboardLength
))
67 for i
in range(self
.keyboardLength
) :
68 upperLeftCorner
= (i
*columnWidth
+ BORDER
, BORDER
)
69 rect
= pygame
.Rect(upperLeftCorner
, (columnWidth
, dispHeight
))
72 self
.keyboardRects
= rects
74 def _initColumns(self
) :
76 hueStep
= FIRST_HUE
/ (self
.keyboardLength
- 1)
77 for i
, rect
in enumerate(self
.keyboardRects
) :
78 hue
= FIRST_HUE
- hueStep
* i
82 def _initCursor(self
) :
83 self
.cursor
= WarpingCursor(blinkMode
=True)
87 def highlightColumn(self
, index
) :
88 for i
, sprite
in enumerate(self
.sprites()) :
89 sprite
.update(i
==index
)
90 self
.draw(pygame
.display
.get_surface())
94 clock
= pygame
.time
.Clock()
97 EventDispatcher
.dispatchEvents()
98 dirty
= self
.draw(pygame
.display
.get_surface())
99 pygame
.display
.update(dirty
)
102 @event_handler(pygame
.KEYDOWN
)
103 def handleKeyDown(self
, event
) :
104 if event
.key
== pygame
.K_q
:
105 self
._running
= False
108 if uni
.isdigit() and int(uni
) <=8 :
109 self
.highlightColumn(int(uni
))
111 @event_handler(pygame
.MOUSEMOTION
)
112 def handleMouseMotion(self
, event
) :
118 class SongPlayingScreen(_PlayingScreenBase
) :
120 def __init__(self
, song
) :
121 super(SongPlayingScreen
, self
).__init
__(song
.distinctNotes
)
124 class SongPlayingScreenTest(_PlayingScreenBase
) :
129 super(SongPlayingScreenTest
, self
).__init
__([o
])
132 class Column(pygame
.sprite
.Sprite
, EventHandlerMixin
) :
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
)
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
)
148 self
.image
= self
.stateOff
151 def update(self
, state
) :
153 self
.image
= self
.stateOn
154 self
.rect
= self
.rectOn
156 self
.image
= self
.stateOff
157 self
.rect
= self
.rectOff
159 @event_handler(pygame
.MOUSEBUTTONDOWN
)
160 def onMouseDown(self
, event
) :
161 if self
.rect
.collidepoint(*event
.pos
) :
164 @event_handler(pygame
.MOUSEBUTTONUP
)
165 def onMouseUp(self
, event
) :
168 def hls_to_rgba_8bits(h
, l
, s
) :
169 #convert to rgb ranging from 0 to 255
170 rgba
= [floor(255 * i
) for i
in hls_to_rgb(h
, l
, s
) + (1,)]