From c3aaeb1ad0bdab785d5bfdcdf3559663ca90571d Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 4 Apr 2015 03:07:07 +0200 Subject: implement icon search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/plugins/image.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/image.py b/src/plugins/image.py index 6d40179..2f30fed 100644 --- a/src/plugins/image.py +++ b/src/plugins/image.py @@ -23,8 +23,13 @@ class Image: Images and icons ''' + theme_preferences = ['hicolor', ..., 'ContrastHigh'] + ''' + :list List of themes in order of preference, `...` marks any that is not listed + ''' + - def __init__(self, file, background = 'black', width = None, height = None): + def __init__(self, file, background = 'black', width = None, height = None, icon = True): ''' Constructor @@ -32,6 +37,8 @@ class Image: @param background:str ImageMagick understandable string for the background colour @param width:int? The width the image should have, `None` to not resize or use `height` @param height:int? The height the image should have, `None` to not resize or use `width` + @parma icon:bool Whether to search for an icon among installed icons rather than + load the image via its pathname ''' import Xlib.X, sys from subprocess import Popen, PIPE @@ -43,6 +50,11 @@ class Image: width = height if width is None else width raster = None + if icon: + file = Image.find_icon(file, width, height, Image.theme_preferences) + if file is None: + raise Exception('No icon found') + convert = ['file', '-'] convert = Popen(convert, stdin = open(file, 'rb'), stdout = PIPE, stderr = sys.stderr) if 'Scalable Vector Graphics' in convert.communicate()[0].decode('utf-8', 'replace'): @@ -111,4 +123,89 @@ class Image: @param y:int The top position of the image ''' bar.window.put_image(bar.gc, x, y, self.width, self.height, self.format, self.depth, 0, self.data) + + + @staticmethod + def find_icon(name, width, height, preferences): + ''' + Find and image for in abstract icon + + @param name:str The name of the icon + @param width:int? The preferred width of the icon, `None` for as large as possible + @param height:int? The preferred height of the icon, `None` for as large as possible + @param preferences:list List of themes in order of preference, `...` marks any that is not listed + @return :str? A pathname for the icon, `None` if none found + ''' + import os, pwd + directories = [] + home = pwd.getpwuid(os.getuid()).pw_dir + directories.append('%s/.icons' % home) + if 'HOME' in os.environ: + if not os.environ['HOME'] == home: + home = os.environ['HOME'] + directories.append('%s/.icons' % home) + directories += ['/usr/local/share/icons', '/usr/share/icons', '/share/icons'] + directories = [d for d in directories if os.path.exists(d) and os.path.isdir(d)] + + height = width if height is None else height + width = height if width is None else width + + dname = name.split('/')[0] if '/' in name else None + iname = name.split('/')[-1] + preferred_size = int((width ** 2 + height ** 2) ** 0.5) if width is not None else None + + def order_themes(themes): + themes, pre, post, state = set(themes), [], [], 0 + for theme in preferences: + if theme is ...: + state = 1 + elif theme in themes: + themes.remove(theme) + (pre if state == 0 else post).append(theme) + return pre + ([] if state == 0 else list(themes)) + post + + def order_sizes(sizes): + sizes = [t(lambda : int(s.split('x')[0]), -1) for s in sizes] + if preferred_size is not None: + high = [s for s in sizes if (s > 0) and (s > preferred_size)] + low = [s for s in sizes if (s > 0) and (s < preferred_size)] + high.sort() + low.sort() + high = ['%ix%i' % (s, s) for s in high] + low = ['%ix%i' % (s, s) for s in reversed(low)] + return ['%ix%i' % (preferred_size, preferred_size)] + high + ['scalable'] + low + else: + sizes.sort() + return ['scalable'] + reversed(sizes) + + def t(f, default): + try: + return f() + except: + return default + + def check(file): + return ('.'.join(file.split('.')[:-1]) if '.' in file else file) == name + + def find_best(directory): + j = lambda *f : '/'.join(list(f)) + for theme in order_themes(t(lambda : os.listdir(directory), [])): + for size in order_sizes(t(lambda : os.listdir(j(directory, theme)), [])): + if dname is not None: + categories = [dname] + else: + categories = t(lambda : os.listdir(j(directory, theme, size)), []) + for cat in ['.'] + categories: + dir = j(directory, theme, size, cat) + files = t(lambda : os.listdir(dir), []) + files = [j(dir, f) for f in files if check(f)] + files = [f for f in files if os.path.isfile(f)] + if len(files) > 0: + files.sort() + return files[0] + return None + + best = [f for f in [find_best(d) for d in directories] if f is not None] + + return None if len(best) == 0 else best[0] -- cgit v1.2.3-70-g09d2