-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpalette.py
258 lines (197 loc) · 6.15 KB
/
palette.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
import color
import math
import tween
class Palette(object):
def __init__(self, *args):
if len(args) == 0:
self.colors = []
elif isinstance(args[0], list):
self.colors = args[0]
else:
self.colors = args
def __repr__(self):
out = "["
comma = ""
for color in self.colors:
out += comma
comma = ","
out += color.hex
out += "]"
return out
@property
def num_colors(self):
return len(self.colors)
def color(self, ix):
return self.colors[ix]
@property
def first(self):
return self.colors[0]
@property
def last(self):
return self.colors[self.num_colors-1]
def color_in_loop(self, progress, blended=True):
"""
This returns a contiguous loop of colors where each one
blend into the next without a hard edge. 0.0 and 1.0 are
the same color.
Think rainbow that is a repeated pattern with no discernible
boundary.
"""
progress = math.modf(progress)[0]
pos = progress * self.num_colors
low_ix = int(math.floor(pos))
high_ix = low_ix + 1
# High might need to wrap
if high_ix >= self.num_colors:
high_ix = 0
interval_distance = pos - low_ix
if blended:
return color.Color(tween.hsvLinear(self.colors[low_ix], self.colors[high_ix], interval_distance))
else:
return self.colors[low_ix]
def color_in_ramp(self, progress, blended=True):
"""
A color from the palette without wrapping smoothly back to the
beginning. Color 0.0 is the first, and color 1.0 is the last,
but these will not be the same color. Color 1.01 will be the
same as color 0.01 though.
"""
# Special case this because it will otherwise get eaten
# by the modf (wrapped to 0). This effectively means that we are
# fudging the very first interval slightly so that the 1.0
# value is the "pure" final answer for the 0 to 1 interval
# but in all other integer cases after 1 the value will be the
# 0 value not the 1 value. This fudging makes life make more
# sense IMHO, and is likely only hit when other code is
# special case explicitly trying to get the 1.0 color.
if progress == 1.0:
return self.colors[self.num_colors-1]
progress = math.modf(progress)[0]
pos = progress * (self.num_colors - 1)
low_ix = int(math.floor(pos))
high_ix = low_ix + 1
# High might need to wrap
if high_ix >= self.num_colors:
high_ix = 0
interval_distance = pos - low_ix
if blended:
return color.Color(tween.hsvLinear(self.colors[low_ix], self.colors[high_ix], interval_distance))
else:
return self.colors[low_ix]
class ChosenPalette(Palette):
def __init__(self):
Palette.__init__(self)
self.cm = None
def __repr__(self):
return "Chosen(" + Palette.__repr__(self) + ")"
def register_controls_model(self, cm):
if self.cm:
self.cm.del_listener(self)
self.cm = cm
if self.cm:
self.cm.add_listener(self)
self.colors = [self.cm.chosen_colors[0], self.cm.chosen_colors[1] ]
else:
self.colors = []
def control_chosen_color_changed(self, ix):
self.colors = [self.cm.chosen_colors[0], self.cm.chosen_colors[1] ]
print("Updated chosen colors palette to " + str(self))
def from_hexes(*hexes):
"""
Given a list of strings, convert those to color objects and create
a Palette from that list
"""
colors = [color.Hex(h) for h in hexes]
return Palette(colors)
# A glue function so we can copy code from Arduino world
def RgbColor(r, g, b):
return color.RGB(r, g, b)
chosen = ChosenPalette()
common = {}
common_key_order = []
def add(name, palette):
common[name] = palette
common_key_order.append(name)
add("Chosen", chosen)
add("Red Blue", from_hexes("#ff0000", "#0000ff"))
add("GRB", from_hexes("#00ff00", "#ff0000", "#0000ff"))
add("RYB", Palette(
RgbColor(255, 0, 0),
RgbColor(255, 64, 0),
RgbColor(255, 128, 0),
RgbColor(255, 191, 0),
RgbColor(255, 255, 0),
RgbColor(128, 212, 25),
RgbColor(0, 168, 51),
RgbColor(21, 132, 102),
RgbColor(42, 95, 153),
RgbColor(85, 48, 140),
RgbColor(128, 0, 128),
RgbColor(191, 0, 64),
))
add("Mardi Gras", Palette(
RgbColor(176, 126, 9),
RgbColor(176, 126, 9),
RgbColor(4, 87, 22),
RgbColor(45, 6, 56),
RgbColor(45, 6, 56),
))
add("White Black", Palette(
RgbColor(0, 0, 0),
RgbColor(96, 96, 96),
RgbColor(255, 255, 255),
))
add("Blues", Palette(
RgbColor(32, 74, 255),
RgbColor(0, 23, 123),
RgbColor(21, 18, 33),
RgbColor(3, 19, 21),
RgbColor(1, 1, 5),
))
add("Pinks", Palette(
RgbColor(229, 92, 87),
RgbColor(255, 59, 51),
RgbColor(191, 43, 87),
RgbColor(127, 48, 27),
RgbColor(32, 7, 7),
))
add("Reds", Palette(
RgbColor(255, 0, 0),
RgbColor(225, 32, 5),
RgbColor(35, 0, 0),
RgbColor(0, 0, 0),
))
###
def common_names_as_step_modes():
"""
Returns a hash of index values to common palette names suitable
for use in the modifier_usage has of a LoopingShow
"""
out = {}
ix = 0
for key in common_key_order:
out[ix] = key
ix += 1
return out
def palette_for_step_mode(mode):
if mode < len(common_key_order):
key = common_key_order[mode]
return common[key]
return chosen
###########
if __name__=='__main__':
print(common)
print()
print(common_key_order)
print(common_names_as_step_modes())
print("Step modes....")
print(palette_for_step_mode(0))
print(palette_for_step_mode(1))
print(palette_for_step_mode(2))
#####
print()
print(" Loop Ramp ")
p = from_hexes("#000000", "#ffffff")
for it in range(0, 25, 1):
t = float(it) / 10
print("{0:.1f} {1} {2}".format(t, p.color_in_loop(t).hex, p.color_in_ramp(t).hex))