def progressbar(left, index, total, right=None, skip=False, charset=3, mid_color=None): if right is None: right = '%s/%s ' % (index + 1, total ) # Because index starts at 0 by default barload = COLS - len(right) if skip: div = int(total / barload) if div <= 0: div = 1 if index > 1 and index % div != 0: return # Only print if progress bar advances left = '(Skipping) %s' % left # Progress section spaced = False # Put spaces in between progress bar characters advance = ['▮', '█', '▰', '⣿', '◼', '.', '⬜'][charset] remain = ['▯', '░', '▱', '⣀', '▭', ' ', '⣿'][charset] load = COLS - len(right) - len(left) mod = 1 if load % 2 == 0 else 0 progress = int(index * barload / total) - len(left) if progress < 0: progress = 0 # Left bar = ANSI.color(left, 'yellow') # Middle if mid_color is not None: bar += ANSI.color(mid_color) for i in range(load): if i == progress and mid_color is not None: bar += ANSI.color('reset') if spaced and i % 2 == mod: bar += ' ' elif i < progress: bar += advance else: bar += remain # Right bar += ANSI.color(right, 'cyan') ANSI.move_column(1) print(bar, end='') sys.stdout.flush()
def load_data(): def load(): try: with open(displays.DATA_FILE, 'rb') as file: global ARRANGEMENT ARRANGEMENT = pickle.load(file) return True except IOError: return False success = load() if success: print(ANSI.color('Successfully loaded!', 'green')) elif displays.find(): success = load() return success
def split(): print('Splitting images...') start = time.time() converted = 0 total = len(IMAGES) for index, image_file in enumerate(IMAGES): fname, ext = os.path.splitext(image_file) base = os.path.basename(fname) skip = False # Check if the glob gets expanded to existing files. # If it does, skip this image (already tiles for it) for some_file in glob.iglob('%s%s_*' % (PREFIX, base)): skip = True break else: # Split the image try: image = Image.open(image_file) except IOError: progressclear() print( ANSI.color('Error: could not open "%s"' % image_file, 'red')) continue tiles = [] imgw, imgh = image.size arrw, arrh = DIMENSIONS # Scale arrangement to best fit image # =================================== # Ratios imgr = imgw * 1.0 / imgh arrr = arrw * 1.0 / arrh scalew = False scaleh = False scale = 1 xoffset = 0 yoffset = 0 new_arrw = 0 new_arrh = 0 # Image is smaller than arrangement if imgw < arrw and imgh < arrh: if imgr <= arrr: scalew = True elif imgr > arrr: scaleh = True # Image is larger than arrangement elif imgw > arrw and imgh > arrh: if imgr <= arrr: scalew = True elif imgr > arrr: scaleh = True # Image is wider than arrangement elif imgw > arrw: scaleh = True # Image is longer than arrangement elif imgh > arrh: scalew = True if scalew: scale = imgw * 1.0 / arrw new_arrh = int(arrh * scale) new_arrw = imgw elif scaleh: scale = imgh * 1.0 / arrh new_arrw = int(arrw * scale) new_arrh = imgh # Center arrangement if image is wider or longer if new_arrw < imgw: xoffset = int((imgw - new_arrw) / 2.0) if new_arrh < imgh: yoffset = int((imgh - new_arrh) / 2.0) new_arrangement = copy.deepcopy(ARRANGEMENT) for display in new_arrangement: display.w = int(display.w * scale) display.h = int(display.h * scale) display.x = int(display.x * scale) + xoffset display.y = int(display.y * scale) + yoffset for tile_index, display in enumerate(new_arrangement): area = ( display.x, # Start x display.y, # Start y display.x + display.w, # End x display.y + display.h # End y ) tile = image.crop(area) tile.save('%s%s_%d%s' % (PREFIX, base, tile_index, ext)) converted += 1 progressbar('"%s"' % image_file, index, total, skip=skip) end = time.time() progressclear() print(ANSI.color('Complete!', 'green')) duration = int(end - start) print('Tiled %s images in %s seconds' % (ANSI.color( str(converted), 'cyan'), ANSI.color(str(duration), 'cyan')))
exit(0) else: # Base64 shared arrangement import base64 fname = displays.DATA_FILE decoded = '' try: decoded = base64.b64decode(config) except Exception: pass if decoded != '': try: with open(fname, 'wb') as file: file.write(decoded) print(ANSI.color('Successfully recorded!', 'green')) exit(0) except Exception: pass print( ANSI.color( 'Error storing arrangement data in "%s"' % fname, 'red')) else: print(usage) exit(0) elif command == 'clean': if num_args == 2: pass elif num_args == 3:
def print_arrangement(_arrangement, max_height=12): lines_printed = 0 # Make a copy of the array to keep the originals intact arrangement = copy.deepcopy(_arrangement) # Scale down dimensions to display in terminal maxh = max([display.h for display in arrangement]) div = maxh / max_height for display in arrangement: display.w = int(display.w / div) display.h = int(display.h / div) display.x = int(display.x / div) display.y = int(display.y / div) # Draw displays from left to right arrangement.sort(key=lambda display: display.x) _arrangement.sort(key=lambda display: display.x) print_inside = all([len(str(_arrangement[i])) <= arrangement[i].w - 2 for i in range(len(arrangement))]) if not print_inside: print(ANSI.color(' '.join([str(display) for display in _arrangement]), 'cyan')) lines_printed += 1 total_lines = max([display.y + display.h for display in arrangement]) lines = {num : ('', 0) for num in range(total_lines)} for index in range(len(arrangement)): display = arrangement[index] _display = _arrangement[index] (w, h, x, y) = (display.w, display.h, display.x, display.y) box = { 'top_left' : '┌', 'top_right' : '┐', 'bottom_left' : '└', 'bottom_right': '┘', 'horiz' : '─', 'vert' : '│' } # Because python 2 cannot use 'nonlocal' keyword outer = { 'index': 0 } def prnt_line(text, num): current_line = lines[ outer['index'] ] current_text = current_line[0] current_num = current_line[1] # Multi-layer arrangements overlap with padding that gets printed new_start = (x - 1) * 2 if ( new_start > 0 and current_num > new_start and current_text[new_start:].strip(' ') == '' # Content is only spaces (OK to overwrite) ): current_text = current_text[:new_start] current_num = new_start lines[ outer['index'] ] = (current_text + text, current_num + num) outer['index'] += 1 # y offset for i in range(y): n = (w - 1) * 2 prnt_line(' ' * n, n) # First line n = (w - 2) * 2 prnt_line(box['top_left'] + box['horiz'] * n + box['top_right'], n + 2) # Middle lines vlines = h - 2 vmid = int(vlines / 2) + (0 if vlines % 2 == 0 else 1) for i in range(vlines): text = '' n = (w - 2) * 2 if (print_inside and i + 1 == vmid): dims = str(_display) text = dims.center(n, ' ') if display.mirrored: text = text.replace(dims, ANSI.color(dims, 'yellow', 'black')) else: text = ' ' * n prnt_line(box['vert'] + text + box['vert'], n + 2) # Last line n = (w - 2) * 2 prnt_line(box['bottom_left'] + box['horiz'] * n + box['bottom_right'], n + 2) # x padding for future displays which go further down while outer['index'] < total_lines: n = (w - 1) * 2 prnt_line(' ' * n, n) for num, line in lines.items(): print(line[0]) lines_printed += total_lines if any([display.mirrored for display in arrangement]): print('Note: %s displays are mirrored' % ANSI.color('highlighted', 'yellow', 'black')) lines_printed += 1 return lines_printed
def find(prefs=None): # Setup # =================================== pbuddy = '/usr/libexec/PlistBuddy' if prefs is None: prefs = '/Library/Preferences/com.apple.windowserver.plist' if not os.path.isfile(pbuddy): print(ANSI.color('Error: could not locate PlistBuddy', 'red')) exit(1) if not os.path.isfile(prefs): print(ANSI.color('Error: could not locate display preferences file', 'red')) exit(1) def test(command): try: subprocess.check_call( command, stdout=DEVNULL, stderr=DEVNULL, shell=True ) except subprocess.CalledProcessError: return False return True # =================================== total_arrangements = 0 pbuddy_print = lambda n: 'print :DisplayAnyUserSets:%d:' % n # Determine number of arrangements while test('"%s" -c "%s" "%s"' % (pbuddy, pbuddy_print(total_arrangements), prefs)): total_arrangements += 1 print('Find your display setup:') found = False for arrangement_index in range(total_arrangements): arrangement = [] print_left = pbuddy_print(arrangement_index) display = 0 while test('"%s" -c "%s%d" "%s"' % (pbuddy, print_left, display, prefs)): display_attr = lambda attr: int( subprocess.check_output( '"%s" -c "%s%d:%s" "%s"' % (pbuddy, print_left, display, attr, prefs), universal_newlines=True, shell=True ).rstrip() ) mirrored = display_attr('Mirrored') == 1 prefix = '' if mirrored else 'Unmirrored' width = display_attr(prefix + 'Width') height = display_attr(prefix + 'Height') originX = display_attr(prefix + 'OriginX') originY = display_attr(prefix + 'OriginY') arrangement.append(Display(width, height, originX, originY, mirrored)) display += 1 # Normalize before printing or saving arrangement = normalize(arrangement) print() num_lines = print_arrangement(arrangement) print() num_lines += 2 # Two print() 's prog = '(%d/%d)' % (arrangement_index + 1, total_arrangements) prog = ANSI.color(prog, 'cyan') read = input('%s Is this your arrangement? [y/N] ' % prog) num_lines += 2 # One for printing the string and one for when you hit enter if read and read in 'yY': found = True fname = DATA_FILE try: with open(fname, 'wb') as file: pickle.dump(arrangement, file, protocol=2) print(ANSI.color('Successfully recorded!', 'green')) except Exception: print(ANSI.color('Error storing arrangement data in "%s"' % fname, 'red')) break else: ANSI.clear(num_lines) if not found: print(ANSI.color('No arrangement chosen. Nothing recorded.', 'red')) return found