import tkinter import lifxlan from PIL import Image as pImage from ..utilities import utils class BulbIconList(tkinter.Frame): # pylint: disable=too-many-ancestors """ Holds the dynamic icons for each Device and Group """ def __init__(self, *args, is_group=False, **kwargs): # Parameters self.is_group = is_group # Constants self.window_width = 285 self.icon_width = 50 self.icon_height = 75 self.pad = 5 self.highlight_color = 95 # Icon Coding self.color_code = { "BULB_TOP": 11, "BACKGROUND": 15 } # Initialization super().__init__(*args, width=self.window_width, height=self.icon_height, **kwargs) self.scrollx = 0 self.scrolly = 0 self.bulb_dict = {} self.canvas = tkinter.Canvas(self, width=self.window_width, height=self.icon_height, scrollregion=(0, 0, self.scrollx, self.scrolly)) hbar = tkinter.Scrollbar(self, orient=tkinter.HORIZONTAL) hbar.pack(side=tkinter.BOTTOM, fill=tkinter.X) hbar.config(command=self.canvas.xview) self.canvas.config(width=self.window_width, height=self.icon_height) self.canvas.config(xscrollcommand=hbar.set) self.canvas.pack(side=tkinter.LEFT, expand=True, fill=tkinter.BOTH) self.current_icon_width = 0 path = self.icon_path() self.original_icon = pImage.open(path).load() self._current_icon = None @property def current_icon(self): """ Returns the name of the currently selected Device/Group """ return self._current_icon def icon_path(self): """ Returns the correct icon path for single Device or Group """ if self.is_group: path = utils.resource_path("res/group.png") else: path = utils.resource_path("res/lightbulb.png") return path def draw_bulb_icon(self, bulb, label): """ Given a bulb and a name, add the icon to the end of the row. """ # Make room on canvas self.scrollx += self.icon_width self.canvas.configure(scrollregion=(0, 0, self.scrollx, self.scrolly)) # Build icon path = self.icon_path() sprite = tkinter.PhotoImage(file=path, master=self.master) image = self.canvas.create_image( (self.current_icon_width + self.icon_width - self.pad, self.icon_height / 2 + 2 * self.pad), image=sprite, anchor=tkinter.SE, tags=[label]) text = self.canvas.create_text(self.current_icon_width + self.pad / 2, self.icon_height / 2 + 2 * self.pad, text=label[:8], anchor=tkinter.NW, tags=[label]) self.bulb_dict[label] = (sprite, image, text) self.update_icon(bulb) # update sizing info self.current_icon_width += self.icon_width def update_icon(self, bulb: lifxlan.Light): """ If changes have been detected in the interface, update the bulb state. """ if self.is_group: return try: # this is ugly, but only way to update icon accurately bulb_color = self.master.bulb_interface.color_cache[bulb.label] bulb_power = self.master.bulb_interface.power_cache[bulb.label] bulb_brightness = bulb_color[2] sprite, image, _ = self.bulb_dict[bulb.label] except TypeError: # First run will give us None; Is immediately corrected on next pass return # Calculate what number, 0-11, corresponds to current brightness brightness_scale = (int((bulb_brightness / 65535) * 10) * (bulb_power > 0)) - 1 color_string = '' for y in range(sprite.height()): # pylint: disable=invalid-name color_string += '{' for x in range(sprite.width()): # pylint: disable=invalid-name # If the tick is < brightness, color it. Otherwise, set it back to the default color icon_rgb = self.original_icon[x, y][:3] if all([(v <= brightness_scale or v == self.color_code["BULB_TOP"]) for v in icon_rgb]) and \ self.original_icon[x, y][3] == 255: bulb_color = bulb_color[0], bulb_color[1], bulb_color[2], bulb_color[3] color = utils.HSBKtoRGB(bulb_color) elif all([v in (self.color_code["BACKGROUND"], self.highlight_color) for v in icon_rgb]) and \ self.original_icon[x, y][3] == 255: color = sprite.get(x, y)[:3] else: color = icon_rgb color_string += utils.tuple2hex(color) + ' ' color_string += '} ' # Write the final colorstring to the sprite, then update the GUI sprite.put(color_string, (0, 0, sprite.height(), sprite.width())) self.canvas.itemconfig(image, image=sprite) def set_selected_bulb(self, lightname): """ Highlight the newly selected bulb icon when changed. """ if self._current_icon: self.clear_selected() sprite, image, _ = self.bulb_dict[lightname] color_string = '' for y in range(sprite.height()): # pylint: disable=invalid-name color_string += '{' for x in range(sprite.width()): # pylint: disable=invalid-name icon_rgb = sprite.get(x, y)[:3] if all([(v == self.color_code["BACKGROUND"]) for v in icon_rgb]) and self.original_icon[x, y][3] == 255: color = (self.highlight_color,) * 3 else: color = icon_rgb color_string += utils.tuple2hex(color) + ' ' color_string += '} ' sprite.put(color_string, (0, 0, sprite.height(), sprite.width())) self.canvas.itemconfig(image, image=sprite) self._current_icon = lightname def clear_selected(self): """ Reset background to original state (from highlighted). """ sprite, image, _ = self.bulb_dict[self._current_icon] color_string = '' for y in range(sprite.height()): # pylint: disable=invalid-name color_string += '{' for x in range(sprite.width()): # pylint: disable=invalid-name icon_rgb = sprite.get(x, y)[:3] if all([(v == self.highlight_color) for v in icon_rgb]) and self.original_icon[x, y][3] == 255: color = (self.color_code["BACKGROUND"],) * 3 else: color = icon_rgb color_string += utils.tuple2hex(color) + ' ' color_string += '} ' sprite.put(color_string, (0, 0, sprite.height(), sprite.width())) self.canvas.itemconfig(image, image=sprite) self._current_icon = None