def hex_to_colour(h, _try_alt=True): """Convert a hex string to colour. Supports inputs as #RGB, #RGBA, #RRGGBB and #RRGGBBAA. If a longer string is invalid, it will try lower lengths. """ if h.startswith('#'): h = h[1:] h_len = len(h) if h_len >= 8: try: return (8, [int(h[i*2:i*2+2], 16) for i in range(4)]) except ValueError: if _try_alt: return hex_to_colour(h[:6]) elif h_len >= 6: try: return (6, [int(h[i*2:i*2+2], 16) for i in range(3)] + [255]) except ValueError: if _try_alt: return hex_to_colour(h[:4]) elif h_len >= 4: try: return (3, [16*j+j for j in (int(h[i:i+1], 16) for i in range(4))]) except ValueError: if _try_alt: return hex_to_colour(h[:3]) elif h_len >= 3: try: return (3, [16*j+j for j in (int(h[i:i+1], 16) for i in range(3))] + [255]) except ValueError: pass return (0, None)
def __init__(self, min_amount, max_amount, colours, offset=0, colour_steps=256, loop=False, cache=None, background=None): if min_amount >= max_amount: colours = [colours[0]] max_amount = min_amount + 1 self.background = background self.max = max_amount self.min = min_amount self.amount = (self.min, self.max) self.amount_diff = self.max - self.min self.colours = colours self.offset = offset self.loop = loop self._len = len(colours) self._len_m = self._len - 1 self.steps = colour_steps * self._len self._step_size = self.amount_diff / self.steps #Cache results for quick access if cache is None: self.cache = [] for i in range(self.steps + 1): self.cache.append(self.calculate_colour(self.min + i * self._step_size)) else: self.cache = cache
def _preview_gradient(self, width, height): """Draw a gradient to test the colours.""" from PIL import Image colours = ColourRange(0, width, self.colours) image = Image.new('RGB', (width, height)) pixels = image.load() height_range = range(height) for x in range(width): colour = colours[x] for y in range(height): pixels[x, y] = colour return image
def __init__(self, x, y, x_len, y_len=None): if y_len is None: y_len = x_len self.x = x self.y = y self.x_len = x_len self.y_len = y_len x_range = tuple(range(x, x + x_len)) y_range = tuple(range(y, y + y_len)) #Cache range (and fix error with radius of 0) i_start = KEY_CORNER_RADIUS + 1 i_end = -KEY_CORNER_RADIUS or max(x + x_len, y + y_len) self.cache = { 'x': x_range[i_start:i_end], 'y': y_range[i_start:i_end], 'x_start': x_range[1:i_start], 'y_start': y_range[1:i_start], 'x_end': x_range[i_end:], 'y_end': y_range[i_end:] }
def fix_poe_mine_build(profile_name, numpad_key): try: _num = 'NUM{}'.format(int(numpad_key)) except ValueError: return False data = LoadData(profile_name, _reset_sessions=False) #Make sure record exists, quick delete if issue is obvious (0 press >0 held) try: if not data['Keys']['All']['Pressed'][_num]: raise KeyError except KeyError: try: del data['Keys']['All']['Held'][_num] except KeyError: pass else: #Count the other numpad items total = {'pressed': 0, 'held': 0, 'count': 0} for i in range(1, 10): if i == numpad_key: continue num = 'NUM{}'.format(i) try: total['pressed'] += data['Keys']['All']['Pressed'][num] total['held'] += data['Keys']['All']['Held'][num] except KeyError: pass else: total['count'] += 1 #Get the average time the numpad is pressed for try: average_press_time = total['held'] / total['pressed'] except ZeroDivisionError: average_press_time = 0 Message('Unable to get an average as no other keypad data exists.') result = input( 'Do you want to delete the numpad key instead (y/n)? ') if not is_yes(result): return False #Assign to numpad key new_held_time = round_int(data['Keys']['All']['Pressed'][_num] * average_press_time) data['Keys']['All']['Held'][_num] = new_held_time return save_data(profile_name, data)
def outline(self, border=0, drop_shadow=1): coordinates = [] if not border: return coordinates #Rounded corners top_left = [ self._circle_offset(x, y, 'TopLeft') for x, y in _CIRCLE['TopLeft']['Outline'] ] top_right = [ self._circle_offset(x, y, 'TopRight') for x, y in _CIRCLE['TopRight']['Outline'] ] bottom_left = [ self._circle_offset(x, y, 'BottomLeft') for x, y in _CIRCLE['BottomLeft']['Outline'] ] bottom_right = [ self._circle_offset(x, y, 'BottomRight') for x, y in _CIRCLE['BottomRight']['Outline'] ] #Rounded corner thickness #This is a little brute force but everything else I tried didn't work r = tuple(range(border)) for x, y in top_left: coordinates += [(x - i, y - j) for i in r for j in r] for x, y in top_right: coordinates += [(x + i, y - j) for i in r for j in r] for x, y in bottom_left: coordinates += [(x - i, y + j) for i in r for j in r] for x, y in bottom_right: coordinates += [(x + i, y + j) for i in r for j in r] #Straight lines for i in r: coordinates += [(_x, self.y - i) for _x in self.cache['x']] coordinates += [(_x, self.y + self.y_len + i) for _x in self.cache['x']] coordinates += [(self.x - i, _y) for _y in self.cache['y']] coordinates += [(self.x + self.x_len + i, _y) for _y in self.cache['y']] return coordinates
def upscale_arrays_to_resolution(arrays, target_resolution, skip=[]): """Upscale a dict of arrays to a certain resolution. The dictionary key must be a resolution, and the values can either be an array or list of arrays. Use skip to ignore array indexes in the list. """ if isinstance(skip, int): skip = [skip] skip = set(skip) #Count number of arrays num_arrays = 0 for resolution, array_list in get_items(arrays): if isinstance(array_list, (list, tuple)): array_len = len(array_list) num_arrays += array_len - len( [i for i in range(array_len) if i in skip]) elif 0 not in skip: num_arrays += 1 #Upscale each array Message('Upscaling arrays to {}x{}...'.format(target_resolution[0], target_resolution[1])) processed = 0 output = [] for resolution, array_list in get_items(arrays): if not isinstance(array_list, (list, tuple)): array_list = [array_list] for i, array in enumerate(array_list): if i in skip: continue processed += 1 Message('Processing array for {}x{} ({}/{})'.format( resolution[0], resolution[1], processed, num_arrays)) zoom_factor = (target_resolution[1] / resolution[1], target_resolution[0] / resolution[0]) upscaled = upscale(array, zoom_factor) output.append(upscaled) return output
def _save_wrapper(q_send, program_name, data, new_program=False): """Handle saving the data files from the thread.""" if program_name is not None and program_name[0] == DISABLE_TRACKING: return NOTIFY(SAVE_PREPARE) NOTIFY.send(q_send) saved = False #Get how many attempts to use if new_program: max_attempts = CONFIG['Save']['MaximumAttemptsSwitch'] else: max_attempts = CONFIG['Save']['MaximumAttemptsNormal'] compressed_data = prepare_file(data) #Attempt to save NOTIFY(SAVE_START) NOTIFY.send(q_send) for i in range(max_attempts): if save_data(program_name, compressed_data, _compress=False): NOTIFY(SAVE_SUCCESS) NOTIFY.send(q_send) saved = True break else: if max_attempts == 1: NOTIFY(SAVE_FAIL) return NOTIFY(SAVE_FAIL_RETRY, CONFIG['Save']['WaitAfterFail'], i, max_attempts) NOTIFY.send(q_send) time.sleep(CONFIG['Save']['WaitAfterFail']) if not saved: NOTIFY(SAVE_FAIL_END)