Module Python-Screen-Stack-Manager.tools

Expand source code
import os
from PIL import ImageOps
from copy import deepcopy
import functools
import time

PATH_TO_PSSM = os.path.dirname(os.path.abspath(__file__))

# ######################## - DECORATORS - ####################################
timer_recall = {}

def timer(func):
    global timer_recall
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        val =  func(*args, **kwargs)
        delay = time.time()-start
        fname = func.__name__
        if fname in timer_recall:
            timer_recall[fname].append(delay)
        else:
            timer_recall[fname] = [delay]
        avg = sum(timer_recall[fname])/len(timer_recall[fname])
        print(f"[DEBUG Timer] {fname} took {delay}s. Average {avg}s on {len(timer_recall[fname])} exec.")
        return val
    return wrapper


def debug(func):
    """Print the function signature and return value"""
    @functools.wraps(func)
    def wrapper_debug(*args, **kwargs):
        args_repr = [repr(a) for a in args]                      # 1
        kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]  # 2
        signature = ", ".join(args_repr + kwargs_repr)           # 3
        print(f"Calling {func.__name__}({signature})")
        value = func(*args, **kwargs)
        print(f"{func.__name__!r} returned {value!r}")           # 4
        return value
    return wrapper_debug


# ########################## - OTHERS - ######################################
def returnFalse(*args): return False


def coordsInArea(click_x, click_y, area):
    """
    Returns a boolean indicating if the click was in the given area
    Args:
        click_x (str): The x coordinate of the click
        click_y (str): The y coordinate of the click
        area (list): The area (of shape : [(x, y), (w, h)])
    """
    [(x, y), (w, h)] = area
    if click_x >= x and click_x < x+w and click_y >= y and click_y < y+h:
        return True
    else:
        return False


def insertStr(string, char, pos):
    """ Returns a string with the characther insterted at said position """
    return string[:pos] + char + string[pos:]


def getRectanglesIntersection(area1, area2):
    (x1, y1), (w1, h1) = area1
    (x2, y2), (w2, h2) = area2
    x0a = max(x1, x2)        # Top left
    x0b = min(x1+w1, x2+w2)  # Bottom right
    y0a = max(y1, y2)        # Top left
    y0b = min(y1+h1, y2+h2)  # Bottom right
    w0 = x0b-x0a
    h0 = y0b-y0a
    if w0 > 0 and h0 > 0:
        return [(x0a, y0a), (w0, h0)]
    else:
        return None


def getPartialEltImg(elt, rectIntersection):
    """
    Returns a PIL image of the the interesection of the Element image and
    the rectangle coordinated given as parameter.
    (Honors invertion)
    Args:
        elt (Element): a PSSM Element
        rectIntersection (list): a [(x, y), (w, h)] array
    """
    [(x, y), (w, h)] = elt.area
    [(x1, y1), (w1, h1)] = rectIntersection
    img = deepcopy(elt.imgData)
    # Then, lets crop it:
    left = + x1 - x
    upper = + y1 - y
    right = left + w1
    lower = upper + h1
    print(x,y,w,h)
    print(left,upper,right,lower)
    img_cropped = img.crop(box=(left, upper, right, lower))
    #img = img.crop((rectIntersection[0][0]-obj.x, rectIntersection[0][1]-obj.y, rectIntersection[1][0]-obj.x, rectIntersection[1][1]-obj.y))
    if elt.isInverted:
        return ImageOps.invert(img_cropped)
    else:
        return img_cropped


def tools_convertXArgsToPX(xPosition, objw, textw, myElt=None):
    """
    Converts xPosition string arguments to numerical values
    Accepted inputs: "left", "center", "right", an inteteger value, or "w/2"
    """
    xPosition = xPosition.lower()
    if xPosition == "left":
        x = 0
    elif xPosition == "center":
        x = int(0.5*objw-0.5*textw)
    elif xPosition == "right":
        x = int(objw-textw)
    else:
        converted = myElt.convertDimension(xPosition)
        x = int(converted)
    return x


def tools_convertYArgsToPX(yPosition, objh, texth, myElt=None):
    """
    Converts yPosition string arguments to numerical values
    """
    yPosition = yPosition.lower()
    if yPosition == "top":
        y = 0
    elif yPosition == "center":
        y = int(0.5*objh-0.5*texth)
    elif yPosition == "bottom":
        y = int(objh-texth)
    else:
        converted = myElt.convertDimension(yPosition)
        y = int(converted)
    return y


def tools_parseKnownImageFile(file):
    """
    Finds the path to a image file if its argument is one of pssm images.
    """
    files = {
        'back': PATH_TO_PSSM + "/icons/back.png",
        'delete': PATH_TO_PSSM + "/icons/delete.jpg",
        "frontlight-down": PATH_TO_PSSM + "/icons/frontlight-down.jpg",
        "frontlight-up": PATH_TO_PSSM + "/icons/frontlight-up.jpg",
        "invert": PATH_TO_PSSM + "/icons/invert.jpg",
        "reboot": PATH_TO_PSSM + "/icons/reboot.jpg",
        "save": PATH_TO_PSSM + "/icons/save.png",
        "touch-off": PATH_TO_PSSM + "/icons/touch-off.png",
        "touch-on": PATH_TO_PSSM + "/icons/touch-on.png",
        "wifi-lock": PATH_TO_PSSM + "/icons/wifi-lock.jpg",
        "wifi-on": PATH_TO_PSSM + "/icons/wifi-on.jpg",
        "wifi-off": PATH_TO_PSSM + "/icons/wifi-off.jpg"
    }
    if file in files:
        return files[file]
    else:
        return file


def tools_parseKnownFonts(font):
    """
    Finds the path to a image file if its argument is one of pssm images.
    """
    fonts = {
        'default': PATH_TO_PSSM + "/fonts/Merriweather-Regular.ttf",
        'default-Regular': PATH_TO_PSSM + "/fonts/Merriweather-Regular.ttf",
        'default-Bold': PATH_TO_PSSM + "/fonts/Merriweather-Bold.ttf",
        'Merriweather-Regular': PATH_TO_PSSM
                                + "/fonts/Merriweather-Regular.ttf",
        'Merriweather-Bold': PATH_TO_PSSM + "/fonts/Merriweather-Bold.ttf"
    }
    if font in fonts:
        return fonts[font]
    else:
        return font


colorsL = {'black': 0, 'white': 255}
colorsRGBA = {'black': (0, 0, 0, 0), 'white': (255, 255, 255, 1)}
for i in range(16):
    s = int(i*255/15)
    colorsL['gray' + str(i)] = s
    colorsRGBA['gray' + str(i)] = (s, s, s, 1)


def get_Color(color, deviceColorType):
    if isinstance(color, str):
        if deviceColorType == "L":
            if color in colorsL:
                return colorsL[color]
            else:
                print("Invalid color, ", color)
                return color
        elif deviceColorType == "RGBA":
            if color in colorsRGBA:
                return colorsRGBA[color]
            else:
                print("Invalid color, ", color)
                return color
    elif isinstance(color, list) or isinstance(color, tuple):
        if deviceColorType == "RGBA":
            if len(color) == 4:
                return color
            else:
                # That's probably RGB
                if isinstance(color, list):
                    return color + [1]
                else:
                    return color + (1)
        else:
            r, g, b = color[0], color[1], color[2]
            gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
            return gray

Functions

def coordsInArea(click_x, click_y, area)

Returns a boolean indicating if the click was in the given area

Args

click_x : str
The x coordinate of the click
click_y : str
The y coordinate of the click
area : list
The area (of shape : [(x, y), (w, h)])
Expand source code
def coordsInArea(click_x, click_y, area):
    """
    Returns a boolean indicating if the click was in the given area
    Args:
        click_x (str): The x coordinate of the click
        click_y (str): The y coordinate of the click
        area (list): The area (of shape : [(x, y), (w, h)])
    """
    [(x, y), (w, h)] = area
    if click_x >= x and click_x < x+w and click_y >= y and click_y < y+h:
        return True
    else:
        return False
def debug(func)

Print the function signature and return value

Expand source code
def debug(func):
    """Print the function signature and return value"""
    @functools.wraps(func)
    def wrapper_debug(*args, **kwargs):
        args_repr = [repr(a) for a in args]                      # 1
        kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]  # 2
        signature = ", ".join(args_repr + kwargs_repr)           # 3
        print(f"Calling {func.__name__}({signature})")
        value = func(*args, **kwargs)
        print(f"{func.__name__!r} returned {value!r}")           # 4
        return value
    return wrapper_debug
def getPartialEltImg(elt, rectIntersection)

Returns a PIL image of the the interesection of the Element image and the rectangle coordinated given as parameter. (Honors invertion)

Args

elt : Element
a PSSM Element
rectIntersection : list
a [(x, y), (w, h)] array
Expand source code
def getPartialEltImg(elt, rectIntersection):
    """
    Returns a PIL image of the the interesection of the Element image and
    the rectangle coordinated given as parameter.
    (Honors invertion)
    Args:
        elt (Element): a PSSM Element
        rectIntersection (list): a [(x, y), (w, h)] array
    """
    [(x, y), (w, h)] = elt.area
    [(x1, y1), (w1, h1)] = rectIntersection
    img = deepcopy(elt.imgData)
    # Then, lets crop it:
    left = + x1 - x
    upper = + y1 - y
    right = left + w1
    lower = upper + h1
    print(x,y,w,h)
    print(left,upper,right,lower)
    img_cropped = img.crop(box=(left, upper, right, lower))
    #img = img.crop((rectIntersection[0][0]-obj.x, rectIntersection[0][1]-obj.y, rectIntersection[1][0]-obj.x, rectIntersection[1][1]-obj.y))
    if elt.isInverted:
        return ImageOps.invert(img_cropped)
    else:
        return img_cropped
def getRectanglesIntersection(area1, area2)
Expand source code
def getRectanglesIntersection(area1, area2):
    (x1, y1), (w1, h1) = area1
    (x2, y2), (w2, h2) = area2
    x0a = max(x1, x2)        # Top left
    x0b = min(x1+w1, x2+w2)  # Bottom right
    y0a = max(y1, y2)        # Top left
    y0b = min(y1+h1, y2+h2)  # Bottom right
    w0 = x0b-x0a
    h0 = y0b-y0a
    if w0 > 0 and h0 > 0:
        return [(x0a, y0a), (w0, h0)]
    else:
        return None
def get_Color(color, deviceColorType)
Expand source code
def get_Color(color, deviceColorType):
    if isinstance(color, str):
        if deviceColorType == "L":
            if color in colorsL:
                return colorsL[color]
            else:
                print("Invalid color, ", color)
                return color
        elif deviceColorType == "RGBA":
            if color in colorsRGBA:
                return colorsRGBA[color]
            else:
                print("Invalid color, ", color)
                return color
    elif isinstance(color, list) or isinstance(color, tuple):
        if deviceColorType == "RGBA":
            if len(color) == 4:
                return color
            else:
                # That's probably RGB
                if isinstance(color, list):
                    return color + [1]
                else:
                    return color + (1)
        else:
            r, g, b = color[0], color[1], color[2]
            gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
            return gray
def insertStr(string, char, pos)

Returns a string with the characther insterted at said position

Expand source code
def insertStr(string, char, pos):
    """ Returns a string with the characther insterted at said position """
    return string[:pos] + char + string[pos:]
def returnFalse(*args)
Expand source code
def returnFalse(*args): return False
def timer(func)
Expand source code
def timer(func):
    global timer_recall
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        val =  func(*args, **kwargs)
        delay = time.time()-start
        fname = func.__name__
        if fname in timer_recall:
            timer_recall[fname].append(delay)
        else:
            timer_recall[fname] = [delay]
        avg = sum(timer_recall[fname])/len(timer_recall[fname])
        print(f"[DEBUG Timer] {fname} took {delay}s. Average {avg}s on {len(timer_recall[fname])} exec.")
        return val
    return wrapper
def tools_convertXArgsToPX(xPosition, objw, textw, myElt=None)

Converts xPosition string arguments to numerical values Accepted inputs: "left", "center", "right", an inteteger value, or "w/2"

Expand source code
def tools_convertXArgsToPX(xPosition, objw, textw, myElt=None):
    """
    Converts xPosition string arguments to numerical values
    Accepted inputs: "left", "center", "right", an inteteger value, or "w/2"
    """
    xPosition = xPosition.lower()
    if xPosition == "left":
        x = 0
    elif xPosition == "center":
        x = int(0.5*objw-0.5*textw)
    elif xPosition == "right":
        x = int(objw-textw)
    else:
        converted = myElt.convertDimension(xPosition)
        x = int(converted)
    return x
def tools_convertYArgsToPX(yPosition, objh, texth, myElt=None)

Converts yPosition string arguments to numerical values

Expand source code
def tools_convertYArgsToPX(yPosition, objh, texth, myElt=None):
    """
    Converts yPosition string arguments to numerical values
    """
    yPosition = yPosition.lower()
    if yPosition == "top":
        y = 0
    elif yPosition == "center":
        y = int(0.5*objh-0.5*texth)
    elif yPosition == "bottom":
        y = int(objh-texth)
    else:
        converted = myElt.convertDimension(yPosition)
        y = int(converted)
    return y
def tools_parseKnownFonts(font)

Finds the path to a image file if its argument is one of pssm images.

Expand source code
def tools_parseKnownFonts(font):
    """
    Finds the path to a image file if its argument is one of pssm images.
    """
    fonts = {
        'default': PATH_TO_PSSM + "/fonts/Merriweather-Regular.ttf",
        'default-Regular': PATH_TO_PSSM + "/fonts/Merriweather-Regular.ttf",
        'default-Bold': PATH_TO_PSSM + "/fonts/Merriweather-Bold.ttf",
        'Merriweather-Regular': PATH_TO_PSSM
                                + "/fonts/Merriweather-Regular.ttf",
        'Merriweather-Bold': PATH_TO_PSSM + "/fonts/Merriweather-Bold.ttf"
    }
    if font in fonts:
        return fonts[font]
    else:
        return font
def tools_parseKnownImageFile(file)

Finds the path to a image file if its argument is one of pssm images.

Expand source code
def tools_parseKnownImageFile(file):
    """
    Finds the path to a image file if its argument is one of pssm images.
    """
    files = {
        'back': PATH_TO_PSSM + "/icons/back.png",
        'delete': PATH_TO_PSSM + "/icons/delete.jpg",
        "frontlight-down": PATH_TO_PSSM + "/icons/frontlight-down.jpg",
        "frontlight-up": PATH_TO_PSSM + "/icons/frontlight-up.jpg",
        "invert": PATH_TO_PSSM + "/icons/invert.jpg",
        "reboot": PATH_TO_PSSM + "/icons/reboot.jpg",
        "save": PATH_TO_PSSM + "/icons/save.png",
        "touch-off": PATH_TO_PSSM + "/icons/touch-off.png",
        "touch-on": PATH_TO_PSSM + "/icons/touch-on.png",
        "wifi-lock": PATH_TO_PSSM + "/icons/wifi-lock.jpg",
        "wifi-on": PATH_TO_PSSM + "/icons/wifi-on.jpg",
        "wifi-off": PATH_TO_PSSM + "/icons/wifi-off.jpg"
    }
    if file in files:
        return files[file]
    else:
        return file