def make_part(self): length = random.randrange(0, self.state.top - self.state.bottom) + 5 if random.randrange(0, 100) < 50: for _ in range(length): yield Color(0, 0, 0, 3500) return brightness = 0 increment = 0.6 / length if not self.blank_lines: hue_range = random.choice(self.hue_ranges) for i in range(length): if self.blank_lines: hue = 0 brightness = 0 else: hue = hue_range.make_hue() tip = False if i == length - 1 and self.line_tip_hue is not None: hue = self.line_tip_hue.make_hue() brightness = 0.8 tip = True color = Color(hue, 1, brightness, 3500) color.tip = tip yield color brightness += increment
def make_canvas(self): canvas = Canvas() for (left, top), (width, height) in self.coords: for i in range(left, left + width): line = self.lines[i] for j in range(top - height, top): got = line[j] if self.options.blinking_pixels: if not getattr(got, "tip", False) and random.randrange(0, 100) < 5: got = Color(got.hue, got.saturation, got.brightness, got.kelvin) got.brightness = 0 canvas[(i, j)] = got return canvas
def canvas(self): # fmt: off points = [ (0, 12, 0), None, None, None, None, (5, 12, 300), # noqa None, None, None, None, (0, 7, 200), None, None, None, None, (5, 7, 10), # noqa None, None, None, None, (2, 4, 90), None, None, None, (6, 4, 30), None, None, None, None, (11, 4, 45), # noqa None, None, (0, 1, 30), None, None, None, None, None, None, None, None, None, None, (11, 1, 89) # noqa ] # fmt: on canvas = Canvas() for point in points: if point is not None: i, j, h = point canvas[(i, j)] = ThemeColor(h, 1, 1, 3500) return canvas
def apply_to_range(self, color, next_color, length): """ Recursively apply two colours to our strip such that we blend between the two colours. """ if length == 1: self.add_hsbk(color) elif length == 2: second_color = ThemeColor.average( [next_color.limit_distance_to(color), color]) self.add_hsbk(color) self.add_hsbk(second_color) else: average = ThemeColor.average([next_color, color]) self.apply_to_range(color, average, length // 2) self.apply_to_range(average, next_color, length - length // 2)
def blur_by_distance(self): """ Similar to blur but will find the 8 closest points as opposed to the 8 surrounding points. """ new_points = {} for (i, j), original in self: distances = self.closest_points(i, j, 8) weighted = list(color_weighting(distances)) new_points[(i, j)] = ThemeColor.average(weighted) self.points = new_points
def blur(self): """ For each point, find the average colour of that point plus all surrounding points. """ new_points = {} for (i, j), original in self: colors = [original for _ in range(2)] for color in self.surrounding_colors(i, j): colors.append(color) new_points[(i, j)] = ThemeColor.average(colors) self.points = new_points
def fill_in_points(self, canvas, left_x, top_y, tile_width, tile_height): """ Fill in the gaps on this canvas by blurring the points on the provided canvas around where our tile is. We blur by finding the 4 closest points for each point on our tile and averaging them. """ for j in range(top_y, top_y - tile_height, -1): for i in range(left_x, left_x + tile_width): distances = canvas.closest_points(i, j, 4) weighted = list(color_weighting(distances)) self[(i, j)] = ThemeColor.average(weighted)
def points_for_tile(self, left_x, top_y, tile_width, tile_height): """ Return a list of 64 hsbk values for this tile For any point on the tile that doesn't have a corresponding point on the canvas return a grey value. This is useful for when we tell the applier to not fill in the gaps. """ result = [] grey = ThemeColor(0, 0, 0.3, 3500) for j in range(top_y, top_y - tile_height, -1): for i in range(left_x, left_x + tile_width): result.append(self.get((i, j), grey)) return result
def assertHues(self, got, *hues): got_hues = [] expected_hues = [] assert len(got) == len(hues) for g, e in zip(got, hues): if e is None: assert g == ThemeColor(0, 0, 0.3, 3500) got_hues.append(0) expected_hues.append(0) else: assert g.saturation == 1 assert g.brightness == 1 assert g.kelvin == 3500 got_hues.append("{:.3f}".format(g.hue)) expected_hues.append("{:.3f}".format(e)) assert got_hues == expected_hues
def apply_theme(self, theme, canvas=None, return_canvas=False): """ If a canvas is not supplied then we create a new canvas with a color func that generates a vertical stripe """ if canvas is None: canvas = Canvas() # We add points for our tiles so that canvas.width and canvas.height still work # They won't have any effect on the tiles themselves because the color_func overrides points grey = ThemeColor(0, 0, 0.3, 3500) for (left_x, top_y), (tile_width, tile_height) in self.coords_and_sizes: canvas[(left_x, top_y)] = grey canvas[(left_x + tile_width, top_y - tile_height)] = grey canvas.set_color_func(self.color_func_generator(theme, canvas)) colors = TileColors() self.add_tiles_from_canvas(colors, canvas) if return_canvas: return colors.tiles, canvas return colors.tiles
from photons_themes.collections import ZoneColors, TileColors from photons_themes.theme import ThemeColor, Theme from photons_app.test_helpers import TestCase import mock describe TestCase, "ZoneColors": it "has colors": colors = ZoneColors() self.assertEqual(colors._colors, []) it "can add a color": colors = ZoneColors() colors.add_hsbk(ThemeColor(0, 1, 1, 3500)) colors.add_hsbk(ThemeColor(100, 1, 1, 3500)) self.assertEqual(colors._colors , [ ThemeColor(0, 1, 1, 3500) , ThemeColor(100, 1, 1, 3500) ] ) describe "returning colors": it "returns with appropriate start_index, end_index": colors = ZoneColors() colors.add_hsbk(ThemeColor(0, 1, 1, 3500)) colors.add_hsbk(ThemeColor(100, 1, 1, 3500)) colors.add_hsbk(ThemeColor(200, 1, 1, 3500)) self.assertEqual(colors.colors
def make_new_color(self, surrounding): if self.new_color_style == "random": return Color(random.randrange(0, 360), 1, 1, 3500) else: return Color.average(surrounding)
def f(i, j): return ThemeColor(i * 10 + j, 1, 1, 3500)
expect_hues = [float("{:.3f}".format(h)) for h in expect] self.assertEqual(got_hues, expect_hues) theme = Theme() @contextmanager def no_shuffle(): shuffled = mock.Mock(name="shuffled", return_value=theme) with mock.patch.object(theme, "shuffled", shuffled): yield shuffled.assert_called_once_with() applier = TileApplierPattern([]) with no_shuffle(): self.assertEqual(applier.make_colors(theme), [ThemeColor(0, 0, 1, 3500)] * 3) theme.add_hsbk(10, 1, 1, 3500) theme.add_hsbk(100, 1, 1, 3500) with no_shuffle(): assertHues(applier.make_colors(theme) , 0.0, 2.5, 5.0, 7.5, 10.0, 32.5, 55.0, 77.5, 100.0 ) with no_shuffle(): assertHues(applier.make_colors(theme, multiplier=4) , 0.0, 2.5, 3.75, 5.0, 7.5, 8.75, 10.0, 32.5, 43.75, 55.0, 77.5, 88.75 ) theme.add_hsbk(30, 1, 1, 3500) theme.add_hsbk(200, 1, 1, 3500)
expect_hues = [float("{:.3f}".format(h)) for h in expect] assert got_hues == expect_hues theme = Theme() @contextmanager def no_shuffle(): shuffled = mock.Mock(name="shuffled", return_value=theme) with mock.patch.object(theme, "shuffled", shuffled): yield shuffled.assert_called_once_with() applier = TileApplierPattern([]) with no_shuffle(): assert applier.make_colors(theme) == [ThemeColor(0, 0, 1, 3500)] * 3 theme.add_hsbk(10, 1, 1, 3500) theme.add_hsbk(100, 1, 1, 3500) with no_shuffle(): # fmt: off assertHues( applier.make_colors(theme), 0.0, 2.5, 5.0, 7.5, 10.0, 32.5, 55.0, 77.5, 100.0 ) # fmt: on with no_shuffle(): # fmt: off assertHues( applier.make_colors(theme, multiplier=4),
# coding: spec from photons_themes.appliers.single import LightApplier from photons_themes.theme import Theme, ThemeColor from photons_app.test_helpers import TestCase import mock describe TestCase, "LightApplier": it "just returns a random color from the theme": color = mock.Mock(name="color") theme = mock.Mock(name="theme") theme.shuffled.return_value = theme theme.random.return_value = color applier = LightApplier() self.assertIs(applier.apply_theme(theme), color) it "returns white if there is no colors in the theme": theme = Theme() applier = LightApplier() self.assertEqual(applier.apply_theme(theme), ThemeColor(0, 0, 1, 3500))
# coding: spec from photons_themes.theme import Theme, ThemeColor from photons_app.test_helpers import TestCase import mock describe TestCase, "ThemeColor": it "takes in hsbk": hue = mock.Mock(name="hue") saturation = mock.Mock(name="saturation") brightness = mock.Mock(name="brightness") kelvin = 3500 color = ThemeColor(hue, saturation, brightness, kelvin) self.assertIs(color.hue, hue) self.assertIs(color.saturation, saturation) self.assertIs(color.brightness, brightness) self.assertIs(color.kelvin, kelvin) it "can return as a dict": hue = mock.Mock(name="hue") saturation = mock.Mock(name="saturation") brightness = mock.Mock(name="brightness") kelvin = 3500 color = ThemeColor(hue, saturation, brightness, kelvin) self.assertEqual(color.as_dict(), {"hue": hue, "saturation": saturation, "brightness": brightness, "kelvin": kelvin})
# coding: spec from photons_themes.appliers.single import LightApplier from photons_themes.theme import Theme, ThemeColor from unittest import mock describe "LightApplier": it "just returns a random color from the theme": color = mock.Mock(name="color") theme = mock.Mock(name="theme") theme.shuffled.return_value = theme theme.random.return_value = color applier = LightApplier() assert applier.apply_theme(theme) is color it "returns white if there is no colors in the theme": theme = Theme() applier = LightApplier() assert applier.apply_theme(theme) == ThemeColor(0, 0, 1, 3500)
it "transitions to each color", theme: applier = StripApplierSplotch(16) with self.not_shuffled(theme): got = applier.apply_theme(theme) # fmt: off self.assertHues( got, 0, 25.0, 50.0, 75.0, 87.5, 100, 125, 150.0, 175.0, 187.5, 200, 225.0, 250.0, 275.0, 287.5, 300 ) # fmt: on it "transitions nicely when the colors aren't sequential", theme: theme.colors.insert(2, ThemeColor(40, 1, 1, 3500)) applier = StripApplierSplotch(16) with self.not_shuffled(theme): got = applier.apply_theme(theme) # fmt: off self.assertHues( got, 0, 25.0, 50.0, 75.0, 100, 85.0, 70.0, 55.0, 40, 80.0, 120.0, 160.0, 200, 225.0, 250.0, 275.0 ) # fmt: on
def get_color(x, y): if want[y][x] is None: return None return ThemeColor(want[y][x], 1, 1, 3500)
# coding: spec from photons_themes.canvas import color_weighting, shuffle_point, Canvas from photons_themes.theme import ThemeColor, Theme from delfick_project.errors_pytest import assertRaises from unittest import mock import random import pytest white = ThemeColor(0, 0, 1, 3500) describe "color_weighting": it "returns nothing if there are no distances": assert list(color_weighting([])) == [] it "returns 0 distance items greatest distance number of times": distances = [ (5, ThemeColor(0, 1, 1, 3500)), (6, ThemeColor(100, 1, 1, 3500)), (0, ThemeColor(300, 1, 1, 3500)), ] cs = list(color_weighting(distances)) assert len([c for c in cs if c.hue == 300]) == 6 distances.append((9, ThemeColor(40, 1, 1, 3400))) cs = list(color_weighting(distances)) assert len([c for c in cs if c.hue == 300]) == 9 it "returns each color more times the closer they are": distances = [
def assertNewHue(self, hue1, hue2, expected_hue): color = ThemeColor(hue1, 0.1, 0.6, 3500) color2 = ThemeColor(hue2, 0.2, 0.5, 4500) limited = color.limit_distance_to(color2) self.assertEqual(limited, ThemeColor(expected_hue, 0.1, 0.6, 3500))
def get_color(x, y): return ThemeColor(want[y][x], 1, 1, 3500)
# coding: spec from photons_themes.theme import Theme, ThemeColor from unittest import mock import pytest describe "ThemeColor": it "takes in hsbk": hue = mock.Mock(name="hue") saturation = mock.Mock(name="saturation") brightness = mock.Mock(name="brightness") kelvin = 3500 color = ThemeColor(hue, saturation, brightness, kelvin) assert color.hue is hue assert color.saturation is saturation assert color.brightness is brightness assert color.kelvin is kelvin it "can return as a dict": hue = mock.Mock(name="hue") saturation = mock.Mock(name="saturation") brightness = mock.Mock(name="brightness") kelvin = 3500 color = ThemeColor(hue, saturation, brightness, kelvin) assert color.as_dict() == { "hue": hue,