Browse Source

Add Image widget, ImageManager, FontManager, SkinManager and other improvements.

Godzil 5 years ago
parent
commit
e92fdef973
48 changed files with 304 additions and 69 deletions
  1. 12 2
      skin/default/config.cfg
  2. 0 0
      skin/default/images/Menu/GameShell/20_Retro Games/MAME.png
  3. 0 0
      skin/default/images/Menu/GameShell/20_Retro Games/MGBA.png
  4. 0 0
      skin/default/images/Menu/GameShell/20_Retro Games/NESTOPIA.png
  5. 0 0
      skin/default/images/Menu/GameShell/CaveStory.png
  6. 0 0
      skin/default/images/Menu/GameShell/Music Player.png
  7. 0 0
      skin/default/images/Menu/GameShell/PowerOFF.png
  8. 0 0
      skin/default/images/Menu/GameShell/Retro Games.png
  9. 0 0
      skin/default/images/Menu/GameShell/RetroArch.png
  10. 0 0
      skin/default/images/Menu/GameShell/Settings.png
  11. 0 0
      skin/default/images/Menu/GameShell/Sleep.png
  12. 0 0
      skin/default/images/Menu/GameShell/TinyCloud.png
  13. 0 0
      skin/default/images/Menu/GameShell/freeDM.png
  14. 0 0
      skin/default/images/sys.py/gameshell/blank.png
  15. 0 0
      skin/default/images/sys.py/gameshell/footbar_icons/footbar.png
  16. 0 0
      skin/default/images/sys.py/gameshell/icons/_L.png
  17. 0 0
      skin/default/images/sys.py/gameshell/icons/_R.png
  18. 0 0
      skin/default/images/sys.py/gameshell/icons/about_bg.png
  19. 0 0
      skin/default/images/sys.py/gameshell/icons/blueselector.png
  20. 0 0
      skin/default/images/sys.py/gameshell/icons/done.png
  21. 0 0
      skin/default/images/sys.py/gameshell/icons/empty.png
  22. 0 0
      skin/default/images/sys.py/gameshell/icons/heart.png
  23. 0 0
      skin/default/images/sys.py/gameshell/icons/icon_sd.png
  24. 0 0
      skin/default/images/sys.py/gameshell/icons/light.png
  25. 0 0
      skin/default/images/sys.py/gameshell/icons/lock.png
  26. 0 0
      skin/default/images/sys.py/gameshell/icons/needwifi_bg.png
  27. 0 0
      skin/default/images/sys.py/gameshell/icons/online.png
  28. 0 0
      skin/default/images/sys.py/gameshell/icons/rom_download.png
  29. 0 0
      skin/default/images/sys.py/gameshell/icons/roundcorners.png
  30. 0 0
      skin/default/images/sys.py/gameshell/icons/scale.png
  31. 0 0
      skin/default/images/sys.py/gameshell/icons/star.png
  32. 0 0
      skin/default/images/sys.py/gameshell/icons/sys.png
  33. 0 0
      skin/default/images/sys.py/gameshell/icons/vol.png
  34. 0 0
      skin/default/images/sys.py/gameshell/titlebar_icons/battery_unknown.png
  35. 0 0
      skin/default/images/sys.py/gameshell/titlebar_icons/soundvolume.png
  36. 0 0
      skin/default/images/sys.py/gameshell/titlebar_icons/wifi.png
  37. 0 0
      skin/default/images/sys.py/gameshell/titlebar_icons/withcharging.png
  38. 0 0
      skin/default/images/sys.py/gameshell/titlebar_icons/without_charging.png
  39. 5 1
      sys.py/UI/__init__.py
  40. 37 11
      sys.py/UI/font_manager.py
  41. 26 0
      sys.py/UI/image.py
  42. 45 0
      sys.py/UI/image_manager.py
  43. 13 15
      sys.py/UI/label.py
  44. 1 0
      sys.py/config.json
  45. 43 30
      sys.py/config.py
  46. BIN
      sys.py/fonts/VarelaRound-Regular.ttf
  47. 23 10
      sys.py/run.py
  48. 99 0
      sys.py/skin_manager.py

+ 12 - 2
skin/default/config.cfg

@@ -1,3 +1,13 @@
 [Colors]
-High = #33a6ff
-White = #ffffff
+High=#33a6ff
+White=#ffffff
+
+[Fonts]
+varela=VarelaRound-Regular.ttf
+veramono=VeraMono.ttf
+noto=NotoSansMono-Regular.ttf
+otocjk=NotoSansCJK-Regular.ttf
+
+[Images]
+blank_icon=sys.py/gameshell/blank.png
+corners_tiles=sys.py/gameshell/icons/roundcorners.png

+ 0 - 0
skin/default/Menu/GameShell/20_Retro Games/MAME.png → skin/default/images/Menu/GameShell/20_Retro Games/MAME.png


+ 0 - 0
skin/default/Menu/GameShell/20_Retro Games/MGBA.png → skin/default/images/Menu/GameShell/20_Retro Games/MGBA.png


+ 0 - 0
skin/default/Menu/GameShell/20_Retro Games/NESTOPIA.png → skin/default/images/Menu/GameShell/20_Retro Games/NESTOPIA.png


+ 0 - 0
skin/default/Menu/GameShell/CaveStory.png → skin/default/images/Menu/GameShell/CaveStory.png


+ 0 - 0
skin/default/Menu/GameShell/Music Player.png → skin/default/images/Menu/GameShell/Music Player.png


+ 0 - 0
skin/default/Menu/GameShell/PowerOFF.png → skin/default/images/Menu/GameShell/PowerOFF.png


+ 0 - 0
skin/default/Menu/GameShell/Retro Games.png → skin/default/images/Menu/GameShell/Retro Games.png


+ 0 - 0
skin/default/Menu/GameShell/RetroArch.png → skin/default/images/Menu/GameShell/RetroArch.png


+ 0 - 0
skin/default/Menu/GameShell/Settings.png → skin/default/images/Menu/GameShell/Settings.png


+ 0 - 0
skin/default/Menu/GameShell/Sleep.png → skin/default/images/Menu/GameShell/Sleep.png


+ 0 - 0
skin/default/Menu/GameShell/TinyCloud.png → skin/default/images/Menu/GameShell/TinyCloud.png


+ 0 - 0
skin/default/Menu/GameShell/freeDM.png → skin/default/images/Menu/GameShell/freeDM.png


+ 0 - 0
skin/default/sys.py/gameshell/blank.png → skin/default/images/sys.py/gameshell/blank.png


+ 0 - 0
skin/default/sys.py/gameshell/footbar_icons/footbar.png → skin/default/images/sys.py/gameshell/footbar_icons/footbar.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/_L.png → skin/default/images/sys.py/gameshell/icons/_L.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/_R.png → skin/default/images/sys.py/gameshell/icons/_R.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/about_bg.png → skin/default/images/sys.py/gameshell/icons/about_bg.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/blueselector.png → skin/default/images/sys.py/gameshell/icons/blueselector.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/done.png → skin/default/images/sys.py/gameshell/icons/done.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/empty.png → skin/default/images/sys.py/gameshell/icons/empty.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/heart.png → skin/default/images/sys.py/gameshell/icons/heart.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/icon_sd.png → skin/default/images/sys.py/gameshell/icons/icon_sd.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/light.png → skin/default/images/sys.py/gameshell/icons/light.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/lock.png → skin/default/images/sys.py/gameshell/icons/lock.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/needwifi_bg.png → skin/default/images/sys.py/gameshell/icons/needwifi_bg.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/online.png → skin/default/images/sys.py/gameshell/icons/online.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/rom_download.png → skin/default/images/sys.py/gameshell/icons/rom_download.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/roundcorners.png → skin/default/images/sys.py/gameshell/icons/roundcorners.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/scale.png → skin/default/images/sys.py/gameshell/icons/scale.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/star.png → skin/default/images/sys.py/gameshell/icons/star.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/sys.png → skin/default/images/sys.py/gameshell/icons/sys.png


+ 0 - 0
skin/default/sys.py/gameshell/icons/vol.png → skin/default/images/sys.py/gameshell/icons/vol.png


+ 0 - 0
skin/default/sys.py/gameshell/titlebar_icons/battery_unknown.png → skin/default/images/sys.py/gameshell/titlebar_icons/battery_unknown.png


+ 0 - 0
skin/default/sys.py/gameshell/titlebar_icons/soundvolume.png → skin/default/images/sys.py/gameshell/titlebar_icons/soundvolume.png


+ 0 - 0
skin/default/sys.py/gameshell/titlebar_icons/wifi.png → skin/default/images/sys.py/gameshell/titlebar_icons/wifi.png


+ 0 - 0
skin/default/sys.py/gameshell/titlebar_icons/withcharging.png → skin/default/images/sys.py/gameshell/titlebar_icons/withcharging.png


+ 0 - 0
skin/default/sys.py/gameshell/titlebar_icons/without_charging.png → skin/default/images/sys.py/gameshell/titlebar_icons/without_charging.png


+ 5 - 1
sys.py/UI/__init__.py

@@ -1,4 +1,4 @@
-__all__ = ["Widget", "label", "container", "screen", "font_manager" "util_funcs"]
+__all__ = ["Widget", "label", "image_manager", "container", "screen", "font_manager", "image", "util_funcs"]
 
 import pygame
 
@@ -6,13 +6,17 @@ from . import widget
 from . import container
 from . import label
 from . import screen
+from . import image
+
 from . import font_manager as FontManager
+from . import image_manager as ImageManager
 from . import util_funcs as utils
 
 Widget = widget.Widget
 Label = label.Label
 Container = container.Container
 Screen = screen.Screen
+Image = image.Image
 
 # Constant values
 Width = 320

+ 37 - 11
sys.py/UI/font_manager.py

@@ -1,22 +1,48 @@
-from . import singleton
-
 import pygame
 
 if not pygame.font.get_init():
     pygame.font.init()
 
-fontpath = {}
-fonts = {}
+__font_files = {}
+__fonts = {}
+__initialized = False
+
+def add_fontfile(name: str, ttffile: str,):
+    global __font_files
+    __font_files[name] = ttffile
 
 
-def add_fontfile(ttffile: str, name: str):
-    fontpath[name] = ttffile
+def __get_font_info(fontname: str):
+    data = fontname.split("_")
+    return data[0], int(data[1])
+
+
+def set_font(asname: str, fontname: str):
+    global __fonts
+    try:
+        __fonts[asname] = __fonts[fontname]
+    except KeyError:
+        fontinfo = __get_font_info(fontname)
+        __fonts[fontname] = pygame.font.Font(__font_files[fontinfo[0]], fontinfo[1])
+        __fonts[asname] = __fonts[fontname]
 
 
 def get_font(fontname: str):
+    global __fonts
     try:
-        return fonts[fontname]
-    except IndexError:
-        tok = fontname.split("_")
-        fonts[fontname] = pygame.font.Font(fonts_path[tok[0]], tok[1])
-        return fonts[fontname]
+        return __fonts[fontname]
+    except KeyError:
+        fontinfo = __get_font_info(fontname)
+        try:
+            __fonts[fontname] = pygame.font.Font(__font_files[fontinfo[0]], fontinfo[1])
+            return __fonts[fontname]
+
+        except KeyError:
+            print("WARN: FontManager - Trying to load '{font}' but not TTF defined for it.".format(font=fontname))
+            return __fonts["default"]
+
+if __initialized is False:
+    # Load default font
+    add_fontfile("default", "fonts/VarelaRound-Regular.ttf")
+    set_font("default", "default_12")
+    __initialized = True

+ 26 - 0
sys.py/UI/image.py

@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+
+import pygame
+from .widget import Widget
+
+class Image(Widget):
+    def __init__(self, x, y, width=1, height=1, text="", bg_color=None, image=None, auto_resize=True):
+        super().__init__(x=x, y=y, width=width, height=height, bg_color=bg_color)
+        self._Image = image
+        self._AutoResize = auto_resize
+        self._Resize()
+
+    def _Resize(self):
+        if not self._AutoResize:
+            return
+
+        if self._Image is not None:
+            self.set_size(self._Image.get_width(), self._Image.get_height())
+
+    def set_image(self, image):
+        self._Image = image
+        self._Resize()
+
+    def Draw(self):
+        super().Draw()
+        self._Parent.get_canvas().blit(self._Image, self._Rect)

+ 45 - 0
sys.py/UI/image_manager.py

@@ -0,0 +1,45 @@
+import pygame
+
+if not pygame.font.get_init():
+    pygame.font.init()
+
+__images = {}
+
+def add_image(name: str, imagefile: str):
+    surf = pygame.image.load(imagefile)
+    __images[name] = surf
+
+
+def get_image(name: str):
+    try:
+        return __images[name]
+    except KeyError:
+        print("WARN: ImageManager': Image '{name}' is not defined".format(name=name))
+        return None
+
+
+def get_sprite(name: str, width: int, height: int, pos: int):
+    try:
+        img = __images[name]
+    except KeyError:
+        print("WARN: ImageManager': Image '{name}' is not defined".format(name=name))
+        return None
+
+    surf = pygame.Surface((width, height))
+    x_count = img.get_width() // width
+    y_count = img.get_height() // height
+
+    pos_x = pos % x_count
+    pos_y = pos // y_count
+    # TODO: Need to make sure the surface is fully transparent, or that we blindly copy the pixel data
+    surf.blit(img, dest=(0, 0), area=(pos_x * width, pos_y * height, width, height), special_flags=pygame.BLEND_ADD)
+
+    return surf
+
+
+
+def del_image(name: str):
+    try:
+        __images[name] = None
+    except KeyError:
+        print("WARN: ImageManager': Trying to remove image '{name}' which was not defined".format(name=name))

+ 13 - 15
sys.py/UI/label.py

@@ -2,34 +2,32 @@
 
 import pygame
 from .widget import Widget
-from .fonts import fonts
 from . import font_manager
 
+
 class Label(Widget):
-    def __init__(self, x, y, width=1, height=10, text="", font_obj=fonts['varela12'],
-                 color=pygame.Color(83, 83, 83), bg_color=None,
+    def __init__(self, x, y, width=1, height=1, text="", font_obj=font_manager.get_font("default"),
+                 color=(83, 83, 83), bg_color=None,
                  auto_resize=True):
-        print(font_manager.get_c())
-        super().__init__(x, y, width, height, color, bg_color)
+        super().__init__(x=x, y=y, width=width, height=height, color=color, bg_color=bg_color)
         self._Text = text
 
         self._Color = color
         self._FontObj = font_obj
-        self.AutoResize = auto_resize
+        self._AutoResize = auto_resize
 
         self._Resize()
 
     def _Resize(self):
-        if not self.AutoResize:
+        if not self._AutoResize:
             return
 
-        if self._FontObj is not None and self._Text is not "":
-            tmp = self._FontObj.render(self._Text, True, self._Color)
-            self.set_size(tmp.get_width(), tmp.get_height())
-        else:
-            self.set_size(10, 1)
-            self._Height = 10
-            self._Width = 1
+        tmp = self._FontObj.render(self._Text, True, self._Color)
+        self.set_size(tmp.get_width(), tmp.get_height())
+
+    def set_font(self, fontname):
+        self._FontObj = font_manager.get_font(fontname)
+        self._Resize()
 
     def GetText(self):
         return self._Text
@@ -44,4 +42,4 @@ class Label(Widget):
         self._FontObj.set_bold(False)
         my_text = self._FontObj.render(self._Text, True, self._Color)
 
-        self._Parent.get_canvas().blit(my_text, (self._PosX, self._PosY, self._Width, self._Height))
+        self._Parent.get_canvas().blit(my_text, self._Rect)

+ 1 - 0
sys.py/config.json

@@ -6,6 +6,7 @@
   "MPD_socket": "/tmp/mpd.socket",
   "UPDATE_URL": "https://raw.githubusercontent.com/clockworkpi/CPI/master/launcher_ver.json",
   "VERSION": "1.0",
+  "skinfolder": "../skin",
   "plugins": [
     "backlight",
     "battery",

+ 43 - 30
sys.py/config.py

@@ -1,39 +1,52 @@
 # -*- coding: utf-8 -*- 
 import json
 
-class Config:
-    DEFAULT_VALUE = """{
-  "CurKeySet": "PC",
-  "DontLeave": false,
-  "BackLight": "/proc/driver/backlight",
-  "Battery": "/sys/class/power_supply/axp20x-battery/uevent",
-  "MPD_socket": "/tmp/mpd.socket",
-  "UPDATE_URL": "https://raw.githubusercontent.com/clockworkpi/CPI/master/launcher_ver.json",
-  "VERSION": "stable-1.0",
-  "SKIN": "default",
-  "plugins": [
-    "backlight",
-    "battery",
-    "wifi",
-  ],
-  "main_applet": "springboard"
+__data = {}
+
+__DEFAULT_VALUE = """{
+"CurKeySet": "PC",
+"DontLeave": false,
+"BackLight": "/proc/driver/backlight",
+"Battery": "/sys/class/power_supply/axp20x-battery/uevent",
+"MPD_socket": "/tmp/mpd.socket",
+"UPDATE_URL": "https://raw.githubusercontent.com/clockworkpi/CPI/master/launcher_ver.json",
+"VERSION": "stable-1.0",
+"SKIN": "default",
+"plugins": [
+"backlight",
+"battery",
+"wifi",
+],
+"main_applet": "springboard"
 }
 """
 
-    def __init__(self):
-        try:
-            with open("config.json", "rt") as f:
-                self._data = json.loads(f.read())
+__config_list = {}
+__initialized = False
+
+def load_config(name="config.json"):
+    global __data
+    try:
+        with open(name, "rt") as f:
+            __data = json.loads(f.read())
+
+    except SystemError:
+        __data = json.loads(__DEFAULT_VALUE)
+
+
+def save(name):
+    global __data
+    with open(name, "wt") as f:
+        f.write(json.dumps(__data))
 
-        except SystemError:
-            self._data = json.loads(self.DEFAULT_VALUE)
 
-    def save(self):
-        with open("config.json", "wt") as f:
-            f.write(json.dumps(self._data))
+def get(key):
+    global __data
+    try:
+        return __data[key]
+    except KeyError:
+        return None
 
-    def get(self, key):
-        try:
-            return self._data[key]
-        except KeyError:
-            return None
+if __initialized == False:
+    load_config("config.json")
+    __initialized = True

BIN
sys.py/fonts/VarelaRound-Regular.ttf


+ 23 - 10
sys.py/run.py

@@ -7,20 +7,20 @@ import sys
 
 import pygame
 
-# from wicd import misc
-import config
-import plugins
-
-import UI
-
 if not pygame.display.get_init():
     pygame.display.init()
 if not pygame.font.get_init():
     pygame.font.init()
 
-conf = config.Config()
-plugins = plugins.LoadPlugins(conf)
+# from wicd import misc
+import config
+import plugins
+import skin_manager as SkinManager
+
+import UI
 
+plugins = plugins.LoadPlugins(config)
+fonts = UI.FontManager
 myscriptname = os.path.basename(os.path.realpath(__file__))
 
 
@@ -93,17 +93,29 @@ def socket_thread(main_screen):
 def main_loop():
     global sound_patch
 
-    screen = UI.Screen(fps=30)
+    screen = UI.Screen(fps=30, bg_color=SkinManager.get_color("active"))
 
     cont = UI.Container(10, 10, 50, 50, bg_color=(192, 192, 192))
 
     lbl = UI.Label(0, 0, auto_resize=True)
     lbl.SetText("Hello the World")
     lbl.set_bgcolor(None)
-    lbl.set_color((0, 255, 0))
+    lbl.set_color(SkinManager.get_color("URL"))
+    lbl.set_font("varela_40")
+
+    img = UI.Image(x=30, y=30, image=UI.ImageManager.get_image("blank_icon"))
+
+    corner_ul = UI.Image(x=0, y=0, image=UI.ImageManager.get_sprite("corners_tiles", 10, 10, 1))
+    # corner_ul = UI.Image(x=0, y=0, image=UI.ImageManager.get_image("corners_tiles"))
+    #img = UI.Image(x=30, y=30, image=UI.ImageManager.get_image("blank_icon"))
+    #img = UI.Image(x=30, y=30, image=UI.ImageManager.get_image("blank_icon"))
+    #img = UI.Image(x=30, y=30, image=UI.ImageManager.get_image("blank_icon"))
 
     cont.add_child(lbl)
 
+    screen.add_child(corner_ul)
+
+    screen.add_child(img)
     screen.add_child(cont)
 
     x = 0
@@ -134,6 +146,7 @@ def init():
         print("This pygame does not support PNG")
         sys.exit()
 
+
     main_loop()
 
 

+ 99 - 0
sys.py/skin_manager.py

@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+import configparser
+import pygame
+import config
+import UI
+
+__Colors = {}
+__name = "default"
+__initialized = False
+
+__SKIN_FONT_FOLDER = "truetype"
+__SKIN_IMAGE_FOLDER = "images"
+
+__SKIN_CFG_COLORS_TAG = "Colors"
+__SKIN_CFG_FONTS_TAG = "Fonts"
+__SKIN_CFG_IMAGES_TAG = "Images"
+
+def __convert_html_color(hexstr):
+    h = hexstr.lstrip('#')
+    return tuple(int(h[i:i + 2], 16) for i in (0, 2, 4))
+
+
+def load_skin(name="default"):
+    global __Colors, __name
+
+    # Set some default values
+    __Colors["high"] = (51, 166, 255)
+    __Colors["text"] = (83, 83, 83)
+    __Colors["front"] = (131, 199, 219)
+    __Colors["url"] = (51, 166, 255)
+    __Colors["line"] = (169, 169, 169)
+    __Colors["title_bg"] = (228, 228, 228)
+    __Colors["active"] = (175, 90, 0)
+    __Colors["white"] = (255, 255, 255)
+
+    __name = name
+
+    # Now read from skin file
+    cfg = configparser.ConfigParser()
+
+    skin_folder = os.path.join(config.get("skinfolder"), name)
+
+    cfgfile = os.path.join(skin_folder, "config.cfg")
+
+    try:
+        cfg.read(cfgfile)
+    except Exception as e:
+
+        if __name == "default":
+            print("INTERNAL ERROR: Can't load default skin. Aborting")
+            sys.exit(-1)
+
+        # TODO: Turn that into a message box
+        print("Skin configuration file for '{name}' is invalid, loading default skin".format(name=name))
+        load_skin("default")
+        return
+
+    # Load skin colors
+    if __SKIN_CFG_COLORS_TAG in cfg.sections():
+        config_color = cfg.options(__SKIN_CFG_COLORS_TAG)
+
+        for color in config_color:
+            try:
+                __Colors[color.lower()] = __convert_html_color(cfg.get(__SKIN_CFG_COLORS_TAG, color))
+            except Exception:
+                print("WARN: Skin '{name}': color value for '{color}' is invalid".format(name=name, color=color))
+
+    # Load skin fonts
+    if __SKIN_CFG_FONTS_TAG in cfg.sections():
+        config_fonts = cfg.options(__SKIN_CFG_FONTS_TAG)
+
+        for font in config_fonts:
+            UI.FontManager.add_fontfile(font, os.path.join(skin_folder, __SKIN_FONT_FOLDER,
+                                                           cfg.get(__SKIN_CFG_FONTS_TAG, font)))
+
+    # Load skin images
+    if __SKIN_CFG_IMAGES_TAG in cfg.sections():
+        config_images = cfg.options(__SKIN_CFG_IMAGES_TAG)
+
+        for image in config_images:
+            UI.ImageManager.add_image(image, os.path.join(skin_folder, __SKIN_IMAGE_FOLDER,
+                                                            cfg.get(__SKIN_CFG_IMAGES_TAG, image)))
+
+
+def get_color(name: str):
+    name = name.lower()
+    if name in __Colors:
+        return __Colors[name]
+    else:
+        print("WARN: Skin '{name}': color '{color}' does not exist".format(name=name, color=name))
+        return (255, 0, 0)
+
+
+if __initialized is False:
+    load_skin("default")
+    __initialized = True