#!/usr/bin/python3
from datetime import datetime
import tkinter as tk
from tkinter import ttk
from tkinter.font import Font
from tkinter.font import ROMAN, Font, BOLD, NORMAL, ITALIC
from tkcalendar import *
from tkcolorpicker import askcolor
import os
from PIL import ImageTk, Image, ImageDraw, ImageColor
RESOURCES_DIR = "resources"


def calculate_coords(canvas, widget, alignment: str, width=None, height=None):
    if widget is not None:
        bounds = canvas.bbox(widget)
        widget_width = bounds[2] - bounds[0]
        widget_height = bounds[3] - bounds[1]
        if alignment == "TopLeft":
            return (0, 0), tk.NW
        elif alignment == "TopCenter":
            return (width/2 - widget_width/2, 0), tk.N
        elif alignment == "TopRight":
            return (width-5-widget_width, 0), tk.NE
        elif alignment == "MiddleLeft":
            return (0, height/2-widget_height/2), tk.W
        elif alignment == "MiddleCenter":
            return (width/2-widget_width/2, height/2-widget_height/2), tk.CENTER
        elif alignment == "MiddleRight":
            return (width-5-widget_width, height/2-widget_height/2), tk.E
        elif alignment == "BottomLeft":
            return (0, height), tk.SW
        elif alignment == "BottomCenter":
            return (width/2-widget_width/2, height-widget_height), tk.S
        elif alignment == "BottomRight":
            return (width-5-widget_width, height-widget_height), tk.SE
    if width is not None:
        if alignment == "TopLeft":
            return (0, 0), tk.NW
        elif alignment == "TopCenter":
            return (width/2, 0), tk.N
        elif alignment == "TopRight":
            return (width-2, 0), tk.NE
        elif alignment == "MiddleLeft":
            return (0, height/2), tk.W
        elif alignment == "MiddleCenter":
            return (width/2, height/2), tk.CENTER
        elif alignment == "MiddleRight":
            return (width-2, height/2), tk.E
        elif alignment == "BottomLeft":
            return (0, height), tk.SW
        elif alignment == "BottomCenter":
            return (width/2, height), tk.S
        elif alignment == "BottomRight":
            return (width-2, height), tk.SE


class Screen(tk.Tk):
    last_window_shown_id = 1

    def __init__(self, id, title, width, height, back_color, on_load_callback=None):
        super(Screen, self).__init__()
        self.id = id
        self.title = title
        self.width = width
        self.height = height
        self.back_color = back_color
        if on_load_callback is not None:
            on_load_callback()
        self.__geom = '{0}x{1}+0+0'.format(width, height)
        self.geometry(self.__geom)
        self.wm_title(string=title)
        if back_color is not None:
            self.configure(bg=back_color)
        self.properties = {
            "id": self.id,
            "width": self.width,
            "height": self.height,
            "backColor": self.back_color,
            "title": self.title,
        }

    def process_set_property(self, property_name, value):
        if property_name == "title":
            self.wm_title(string=value)
        elif property_name == "width":
            self.__geom = '{}x{}+0+0'.format(value, self.properties["height"])
            self.geometry(self.__geom)
        elif property_name == "height":
            self.__geom = '{}x{}+0+0'.format(self.properties["width"], value)
            self.geometry(self.__geom)
        elif property_name == "backColor":
            if value is not None:
                self.configure(bg=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        self.properties[property_name] = value
        self.process_set_property(property_name, value)

    def get_property(self, property_name):
        return self.properties[property_name]


class CompiledButton(tk.Canvas):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height, border_enabled, border_size, border_color, radius_left=None, radius_right=None):
        # self.btn_frame = tk.Frame(win, highlightbackground=border_color,
        #                           highlightthickness=border_size if border_enabled else 0, bd=0)
        super(CompiledButton, self).__init__(win)
        self.id = id
        self.back_color = back_color
        self.pos_x = pos_x
        self.pos_y = pos_y
        self.width = width
        self.height = height
        self.border_enabled = border_enabled
        self.border_size = border_size
        self.border_color = border_color
        self.parent_bg = win['bg']
        self.properties = {
            "id": self.id,
            "width": self.width,
            "height": self.height,
            "backColor": self.back_color,
            "posX": self.pos_x,
            "posY": self.pos_y,
            "border": {
                "enabled": self.border_enabled,
                "borderSize": self.border_size,
                "borderColor": self.border_color
            },
            "image": {
                "enabled": False,
                "imageName": "",
                "imageAlign": "",
                "width": width,
                "height": height
            },
            "background": False,
            "bgImageName": "",
            "textFont": {
                "bold": False,
                "italic": False,
                "size": 12,
                "family": "Arial",
                "textAlign": ""
            },
            "text": "",
            "foreColor": "#000000"
        }
        self.btn_width = width
        self.btn_height = height
        self.radius_left = None
        if radius_left is not None:
            self.radius_left = radius_left
            self.radius_right = radius_right
            self.draw_rounded_button()
            self.config(bg=self.parent_bg, relief='ridge',
                        highlightthickness=0)
        # self.btn_frame.config(bg=back_color)
        # self.btn_frame.place(x=pos_x, y=pos_y, width=width, height=height)
        self.back_color = back_color
        # self.configure(bg=back_color, width=width,
        #                height=height, relief=tk.SUNKEN)
        self.place(x=pos_x, y=pos_y, width=width, height=height)
        self.bg_image = self.create_image(0, 0)
        self.btn_img = self.create_image(0, 0)
        self.btn_text = self.create_text(0, 0)

    # def moveto(self, _object, new_x, new_y):
        #     # Get the current object position
    #     x, y, *_ = self.bbox(_object)
    #     # Move the object
    #     self.move(_object, new_x-x, new_y-y)
    def draw_rounded_button(self):
        rad_tl, rad_bl = 2*self.radius_left[0], 2*self.radius_left[1]
        rad_tr, rad_br = 2*self.radius_right[0], 2*self.radius_right[1]
        padding = 2
        color = self.back_color
        # Top line
        # self.create_line(0 + rad_tl/2, 0+padding, 0 + self.width - rad_tr/2, 0+padding, fill=color, width=1)
        # # Right line
        # self.create_line(self.width - rad_tr/2-padding, 0+rad_tr+padding, 0 + self.width - rad_tr/2-padding, 0+self.height-rad_br/2, fill=color, width=1)
        # # Bottom line
        # self.create_line(0 + rad_bl/2, 0+padding, 0 + self.width - rad_tr/2, 0+padding, fill=color, width=1)
        # self.create_line(self.pos_x + width, self.pos_y + radius, self.pos_x + width, self.pos_y + height - radius, fill=outline)
        # self.create_line(self.pos_x + radius, self.pos_y + height, self.pos_x + width - radius, self.pos_y + height, fill=outline)
        # self.create_line(self.pos_x, self.pos_y + radius, self.pos_x, self.pos_y + height - radius, fill=outline)
        # print(
        #     # Top left corner HIGH
        #     0 + rad_tl/2,
        #     # Y
        #     0+padding,

        #     # Top right corner HIGH
        #     # X
        #     0 + self.width - rad_tr/2,
        #     # Y
        #     0 + padding,

        #     # Top right corner LOW
        #     # X
        #     self.width - rad_tr/2,
        #     # Y
        #     0 + rad_tr + padding,

        #     # Bottom right corner HIGH
        #     # X
        #     0 + self.width - padding,
        #     # Y
        #     0 + self.height - rad_br/2,

        #     # Bottom right corner LOW
        #     # X
        #     0 + self.width - rad_br/2,
        #     # Y
        #     0 + self.height - padding,

        #     # Bottom left corner LOW
        #     # X
        #     0 + rad_bl/2,
        #     # Y
        #     0 + self.height - padding,

        #     # Bottom left corner HIGH
        #     # X
        #     0+padding,
        #     # Y
        #     0 + self.height - rad_bl/2,

        #     # Top left corner LOW
        #     # X
        #     0+padding,
        #     # Y
        #     0 + padding + rad_tl/2)
        # self.btn_center = self.create_polygon(
        #     (
        #         # Top left corner HIGH
        #     0 + rad_tl/2 + padding,
        #     # Y
        #     0+padding,

        #     # Top right corner HIGH
        #     # X
        #     0 + self.width - rad_tr/2 - padding,
        #     # Y
        #     0 + padding,

        #     # Top right corner LOW
        #     # X
        #     self.width - rad_tr/2 + padding,
        #     # Y
        #     0 + rad_tr + padding,

        #     # Bottom right corner HIGH
        #     # X
        #     0 + self.width - padding,
        #     # Y
        #     0 + self.height - rad_br/2,

        #     # Bottom right corner LOW
        #     # X
        #     0 + self.width - rad_br/2,
        #     # Y
        #     0 + self.height - padding,

        #     # Bottom left corner LOW
        #     # X
        #     0 + rad_bl/2,
        #     # Y
        #     0 + self.height - padding,

        #     # Bottom left corner HIGH
        #     # X
        #     0+padding,
        #     # Y
        #     0 + self.height - rad_bl/2,

        #     # Top left corner LOW
        #     # X
        #     0+padding,
        #     # Y
        #     0 + padding + rad_tl/2
        #     ),
        #     fill=color)
        if rad_tl != 0:
            self.btn_tl = self.create_arc((padding, padding+rad_tl, padding+rad_tl, padding),
                                          start=90, extent=90, fill=color, outline=self.back_color, style=tk.CHORD)
        if rad_tr != 0:
            self.btn_tr = self.create_arc((self.btn_width-padding-rad_tr, padding, self.btn_width-padding,
                                           padding+rad_tr), start=0, extent=90, fill=color, outline=self.back_color, style=tk.CHORD)
        if rad_br != 0:
            self.btn_br = self.create_arc((self.btn_width-padding, self.btn_height-rad_br -
                                           padding, self.btn_width-padding-rad_br,
                                           self.btn_height-padding), start=270, extent=90, fill=color, outline=self.back_color, style=tk.CHORD)
            # self.btn_br = self.create_arc((self.btn_width-padding, self.btn_height-rad_br-padding, self.btn_width-padding-rad_br,
            #                                self.btn_height-padding), start=270, extent=90, fill=color, outline=color, style=tk.CHORD)
        if rad_bl != 0:
            self.btn_bl = self.create_arc((padding+rad_bl, self.btn_height -
                                           padding,
                                           padding, self.btn_height-padding-rad_bl), start=180, extent=90, fill=color, outline=self.back_color, style=tk.CHORD)
            # self.btn_bl = self.create_arc((padding, self.btn_height-padding*2-rad_bl/2, padding+rad_bl, self.btn_height -
            #                                padding), start=180, extent=90, fill=color, outline=color, style=tk.CHORD)
        points = (
            #
            padding, padding+rad_tl/2, padding+rad_tl/2, padding,
            #
            self.btn_width-padding-rad_tr/2, padding, self.btn_width-padding/2,
            padding+rad_tr/2,
            #
            self.btn_width-padding, self.btn_height-rad_br/2 - \
            padding, self.btn_width-padding-rad_br/2,
            self.btn_height-padding/2,
            #
            padding+rad_bl/2, self.btn_height -
            padding/2,
            padding, self.btn_height-padding-rad_bl/2,
        )
        self.btn_center = self.create_polygon(
            points,
            fill=color,
            # outline=self.border_color
        )

    def display_text(self, text, coords, font_family, font_size, color, is_bold, is_italic, anchor=tk.CENTER, text_align="MiddleCenter"):
        font = Font(family=font_family, size=font_size-6,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        self.text = text
        self.coords = coords
        self.font_family = font_family
        self.font_size = font_size-6
        self.color = color
        self.is_bold = is_bold
        self.is_italic = is_italic
        self.anchor = anchor
        pos_x, pos_y = coords
        self.properties.update({
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size,
                "family": font_family,
                "textAlign": text_align
            },
            "text": text,
            "foreColor": color
        })
        self.moveto(self.btn_text, pos_x, pos_y)
        self.itemconfigure(self.btn_text,
                           anchor=anchor, text=text, fill=color, font=font)
        self.set_property("textFont/textAlign", text_align)

    def display_image(self, img_name, width, height, coords, anchor=tk.CENTER, image_align="MiddleRight"):
        self.img_name = img_name
        self.img_width = width
        self.img_height = height
        self.img_coords = coords
        self.img_anchor = anchor
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.image_tk = ImageTk.PhotoImage(image)
        pos_x, pos_y = coords
        self.properties.update({
            "image": {
                "enabled": True,
                "imageName": img_name,
                "imageAlign": image_align,
                "width": width,
                "height": height
            }
        })
        self.moveto(self.btn_img, pos_x, pos_y)
        self.itemconfigure(self.btn_img, anchor=anchor, image=self.image_tk)
        self.set_property("image/imageAlign", image_align)

    def display_bg_image(self, img_name, width, height):
        self.bg_img_name = img_name
        self.bg__img_width = width
        self.bg_img_height = height
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.bg_image_tk = ImageTk.PhotoImage(image)
        self.properties.update({
            "background": True,
            "bgImageName": img_name
        })
        self.moveto(self.bg_image, width/2, height/2)
        self.itemconfigure(self.bg_image, image=self.image_tk)

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "image":
                if sub_property == "enabled":
                    if not value:
                        self.itemconfigure(self.btn_img, state="hidden")
                    else:
                        self.itemconfigure(self.btn_img, state="normal")
                elif sub_property == "imageAlign":
                    coords_image, anchor_image = calculate_coords(self, None,
                                                                  value, self.properties[property_name]["width"], self.properties[property_name]["height"])
                    self.moveto(self.btn_img, coords_image[0], coords_image[1])
                    self.itemconfigure(self.btn_img, anchor=anchor_image)
                if self.properties[property_name]["enabled"]:
                    if sub_property == "imageName":
                        image = Image.open(os.path.join(RESOURCES_DIR, value))
                        image = image.resize(
                            (self.properties[property_name]["width"], self.properties[property_name]["height"]))
                    elif sub_property == "width":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (value, self.properties[property_name]["height"]))
                    elif sub_property == "height":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (self.properties[property_name]["width"], value))

                    self.image_tk = ImageTk.PhotoImage(image)
                    self.itemconfig(self.btn_img, image=self.image_tk)
            elif property_name == "textFont":
                if sub_property == "textAlign":
                    coords_text, anchor_text = calculate_coords(self, self.btn_text,
                                                                value, self.properties["width"], self.properties["height"])
                    self.moveto(self.btn_text, int(
                        coords_text[0]), int(coords_text[1]))
                    self.itemconfigure(self.btn_text, anchor=anchor_text)
                    self.moveto(self.btn_text, int(
                        coords_text[0]), int(coords_text[1]))
                    self.itemconfigure(self.btn_text, anchor=anchor_text)
                else:
                    font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                                weight=NORMAL if not self.properties[property_name]["bold"] else BOLD, slant=ROMAN if not self.properties[property_name]["italic"] else ITALIC)
                    self.itemconfigure(self.btn_text, font=font)
            elif property_name == "border":
                pass
                # if sub_property == "enabled":
                #     if value:
                #         self.btn_frame.configure(highlightthickness=1)
                #     else:
                #         print("here")
                #         self.btn_frame.configure(highlightthickness=0)
                # elif sub_property == "borderSize":
                #     self.btn_frame.configure(highlightthickness=value)
                # elif sub_property == "borderColor":
                #     self.btn_frame.configure(highlightbackground=value)
        else:
            if property_name == "width":
                # self.btn_frame.configure(width=value)
                self.place(x=self.pos_x, y=self.pos_y,
                           width=value, height=self.height)
                self.configure(width=value)
            elif property_name == "height":
                self.place(x=self.pos_x, y=self.pos_y,
                           width=self.width, height=value)
                # self.btn_frame.configure(height=value)
                self.configure(height=value)
            elif property_name == "backColor":
                if self.radius_left is not None:
                    self.itemconfigure(
                        self.btn_center, fill=value, outline=value)
                    self.itemconfigure(self.btn_tl, fill=value, outline=value)
                    self.itemconfigure(self.btn_tr, fill=value, outline=value)
                    self.itemconfigure(self.btn_bl, fill=value, outline=value)
                    self.itemconfigure(self.btn_br, fill=value, outline=value)
                else:
                    self.configure(bg=value)
                    # self.itemconfigure(self, bg)
                # self.btn_frame.configure(bg=value)
                # self.configure(bg=value)
            elif property_name == "posX":
                self.place(x=value, y=self.pos_y,
                           width=self.width, height=self.height)
                # self.btn_frame.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.place(x=self.pos_x, y=value,
                           width=self.width, height=self.height)
                # self.btn_frame.place(x=self.properties["posX"], y=value)
            elif property_name == "text":
                self.itemconfig(self.btn_text, text=value)
            elif property_name == "foreColor":
                self.itemconfig(self.btn_text, fill=value)
            elif property_name == "background":
                if value:
                    self.itemconfigure(self.bg_image, state="normal")
                else:
                    self.itemconfigure(self.bg_image, state="hidden")
            elif property_name == "bgImageName":
                image = Image.open(os.path.join(RESOURCES_DIR, value))
                image = image.resize(
                    (self.properties["width"], self.properties["height"]))
                self.bg_image_tk = ImageTk.PhotoImage(image)
                self.itemconfigure(self.bg_image, image=self.image_tk)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledToggleButton(tk.Canvas):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height, border_enabled, border_size, border_color, radius, back_color_2, toggler_color_on, toggler_color_off, checked):
        # self.btn_frame = tk.Frame(win, highlightbackground=border_color,
        #                           highlightthickness=border_size if border_enabled else 0, bd=0)
        super(CompiledToggleButton, self).__init__(win)
        self.id = id
        self.back_color = back_color
        self.pos_x = pos_x
        self.pos_y = pos_y
        self.width = width
        self.height = height
        self.border_enabled = border_enabled
        self.border_size = border_size
        self.border_color = border_color
        self.parent_bg = win['bg']
        self.properties = {
            "id": self.id,
            "width": self.width,
            "height": self.height,
            "backColor": self.back_color,
            "posX": self.pos_x,
            "posY": self.pos_y,
            "backColorTwo": back_color_2,
            "togglerBackColorOn": toggler_color_on,
            "togglerBackColorOff": toggler_color_off,
            "border": {
                "enabled": self.border_enabled,
                "borderSize": self.border_size,
                "borderColor": self.border_color,
                "radius": {
                    "bl": radius
                },
            },
            "image": {
                "enabled": False,
                "imageName": "",
                "imageAlign": "",
                "width": width,
                "height": height
            },
            "background": False,
            "bgImageName": "",
            "textFont": {
                "bold": False,
                "italic": False,
                "size": 12,
                "family": "Arial",
                "textAlign": ""
            },
            "text": "",
            "foreColor": "#000000",
            "checked": checked
        }
        self.btn_width = width
        self.btn_height = height
        self.radius_left = None
        # if radius is not None:
        self.draw_button(checked)
        self.config(bg=self.parent_bg, relief='ridge',
                    highlightthickness=0)
        # self.btn_frame.config(bg=back_color)
        # self.btn_frame.place(x=pos_x, y=pos_y, width=width, height=height)
        self.back_color = back_color
        # self.configure(bg=back_color, width=width,
        #                height=height, relief=tk.SUNKEN)
        self.place(x=pos_x, y=pos_y, width=width, height=height)
        self.bind('<ButtonRelease-1>', self.change_state)

    def change_state(self, event):
        self.properties["checked"] = not self.properties["checked"]
        self.draw_button(self.properties["checked"])

    def draw_button(self, checked):
        try:
            self.delete(self.toggler_off)
        except:
            pass
        try:
            self.delete(self.toggler_on)
        except:
            pass
        try:
            self.delete(self.toggler_off)
        except:
            pass
        try:
            self.delete(self.back_button_on)
        except:
            pass
        padding = 4
        # back_radius = self.properties["border"]["radius"]["bl"]
        # toggle_radius = self.properties["border"]["radius"]["bl"]-padding
        back_radius = self.properties["width"]/4-1
        toggle_radius = self.properties["width"]/4-padding
        center_back_off = (
            self.properties["width"]/4, self.properties["height"]/2)
        center_back_on = (
            self.properties["width"]-self.properties["width"]/4, self.properties["height"]/2)
        center_toggler_off = (
            self.properties["width"]/4, self.properties["height"]/2)
        center_toggler_on = (
            self.properties["width"]-self.properties["width"]/4, self.properties["height"]/2)
        self.button_center = self.create_rectangle(self.properties["width"]/4, 1, self.properties["width"]-self.properties["width"]/4, self.properties["height"],
                                                   fill=self.properties["backColor"] if not self.properties["checked"] else self.properties["backColorTwo"], outline=self.properties["backColor"] if not self.properties["checked"] else self.properties["backColorTwo"])
        self.back_button_off = self.create_oval(center_back_off[0] - back_radius,
                                                center_back_off[1] -
                                                back_radius,
                                                center_back_off[0] +
                                                back_radius,
                                                center_back_off[1] +
                                                back_radius,
                                                fill=self.properties["backColor"] if not self.properties[
                                                    "checked"] else self.properties["backColorTwo"],
                                                outline=self.properties["backColor"] if not self.properties["checked"] else self.properties["backColorTwo"])

        self.back_button_on = self.create_oval(center_back_on[0] - back_radius,
                                               center_back_on[1] -
                                               back_radius,
                                               center_back_on[0] +
                                               back_radius,
                                               center_back_on[1] +
                                               back_radius,
                                               fill=self.properties["backColorTwo"] if self.properties[
                                                   "checked"] else self.properties["backColor"],
                                               outline=self.properties["backColorTwo"] if self.properties["checked"] else self.properties["backColor"])
        if checked == False:
            self.toggler_off = self.create_oval(center_toggler_off[0] - toggle_radius,
                                                center_toggler_off[1] -
                                                toggle_radius,
                                                center_toggler_off[0] +
                                                toggle_radius,
                                                center_toggler_off[1] +
                                                toggle_radius,
                                                fill=self.properties["togglerBackColorOff"], outline=self.properties["togglerBackColorOff"])
        else:
            self.toggler_on = self.create_oval(center_toggler_on[0] - toggle_radius,
                                               center_toggler_on[1] -
                                               toggle_radius,
                                               center_toggler_on[0] +
                                               toggle_radius,
                                               center_toggler_on[1] +
                                               toggle_radius,
                                               fill=self.properties["togglerBackColorOn"], outline=self.properties["togglerBackColorOn"])

    def process_set_property(self, property_name, value, sub_property=None):
        if property_name == "width":
            # self.btn_frame.configure(width=value)
            self.place(x=self.pos_x, y=self.pos_y,
                       width=value, height=self.height)
            self.configure(width=value)
        elif property_name == "height":
            self.place(x=self.pos_x, y=self.pos_y,
                       width=self.width, height=value)
        elif property_name == "posX":
            self.place(x=value, y=self.pos_y,
                       width=self.width, height=self.height)
            # self.btn_frame.place(x=value, y=self.properties["posY"])
        elif property_name == "posY":
            self.place(x=self.pos_x, y=value,
                       width=self.width, height=self.height)
        self.draw_button()

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledTrackbar(ttk.Scale):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height, fore_color, init_value, orientation, min_val, max_val):
        self.track_frame = tk.Frame(win)
        ttk.Scale.__init__(self, self.track_frame)
        self.id = id
        self.back_color = back_color
        self.pos_x = pos_x
        self.pos_y = pos_y
        self.width = width
        self.height = height
        # self.parent_bg = win['bg']
        self.properties = {
            "id": self.id,
            "width": self.width,
            "height": self.height,
            "backColor": self.back_color,
            "foreColor": fore_color,
            "posX": self.pos_x,
            "posY": self.pos_y,
            "text": "",
            "foreColor": "#000000",
            "value": init_value,
            "minimum": min_val,
            "maximum": max_val,
        }
        self.btn_width = width
        self.btn_height = height
        self.value = tk.IntVar(self.track_frame, value=init_value)
        self.config(variable=self.value, orient=orientation,
                    from_=min_val, to=max_val)
        img = Image.new("RGBA", (width, height),
                        ImageColor.getcolor(win['bg']+'ff', "RGBA"))
        _img2 = Image.new("RGBA", (10, height) if orientation == 'horizontal' else (width-1, 1),
                          ImageColor.getcolor(win['bg']+'ff', "RGBA"))
        # create  rectangleimage
        img1 = ImageDraw.Draw(img, 'RGBA')
        img2 = ImageDraw.Draw(_img2, 'RGBA')
        shape = [(4, 4), (width-4, height-4)] 
        shape2 = [(0, 0), (10, height)] if orientation == 'horizontal' else [(4, 0), (width, 1)]
        img1.rounded_rectangle(shape, fill=win['bg']+'ff', outline=back_color, width=1, radius=4)
        img2.rounded_rectangle(shape2, fill=fore_color+'ff', radius=1)
        self.img_trough = ImageTk.PhotoImage(image=img, width=width-4, height=height-4)
        self.img_slider = ImageTk.PhotoImage(image=_img2)
        self.__style = ttk.Style(self.track_frame)
        # create scale elements
        self.__style.element_create(
            str(self)+str(id)+'.custom.Scale.trough', 'image', self.img_trough)
        self.__style.element_create(
            str(self)+str(id)+'.custom.Scale.slider', 'image', self.img_slider)
        # create custom layout
        self.__style.layout(str(self)+str(id)+'.custom.'+orientation.title()+'.TScale',
                            [(str(self)+str(id)+'.custom.Scale.trough', {'sticky': 'ew'}),
                             (str(self)+str(id)+'.custom.Scale.slider',
                                {'side': 'left' if orientation == 'horizontal' else 'top', 'sticky': '',
                                 'children': [(str(self)+str(id)+'.custom.'+orientation.title()+'.Scale.label', {'sticky': ''})]
                                 })])
        self._style_name = '{}.custom.{}.TScale'.format(
            str(self)+str(id), orientation.title())  # unique style name to handle the text
        self['style'] = self._style_name
        # self.value.trace_add('write', self._update_text)
        # self._update_text()
        self.track_frame.place(x=pos_x, y=pos_y, width=width, height=height)
        self.pack(side='left')

    # def _update_text(self, *args):
    #     self.__style.configure(
    #         self._style_name, text="{:.1f}".format(self.value.get()))

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        elif property_name == 'value':
            return self.value.get()
        else:
            return self.properties[property_name]


class CompiledTextBox(tk.Frame):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height, password_char="", read_only=False):
        super(CompiledTextBox, self).__init__(win)
        # self.text_frame = tk.Frame(self)
        self.id = id
        self.configure(bg=back_color, width=width,
                       height=height)
        self.text_frame = tk.Frame(self, width=width, height=height)
        self.text_frame.configure(bg=back_color, width=width,
                                  height=height)
        self.password_char = password_char
        self.read_only = read_only
        self.width = width
        self.height = height
        self.place(x=pos_x, y=pos_y)
        self.text_frame.pack_propagate(False)
        self.text_frame.pack()
        self.entry_value = tk.StringVar()
        self.properties = {
            "id": self.id,
            "width": self.width,
            "height": self.height,
            "backColor": back_color,
            "posX": pos_x,
            "posY": pos_y,
            "passwordChar": password_char,
            "readOnly": read_only,
            "textFont": {
                "bold": False,
                "italic": False,
                "size": 12,
                "family": "Arial",
                "textAlign": ""
            },
            "text": "",
            "foreColor": "#000000"
        }

    def display_text(self, text, coords, font_family, font_size, color, is_bold, is_italic, anchor=tk.CENTER, text_align="MiddleCenter"):
        font = Font(family=font_family, size=font_size-6,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        pos_x, pos_y = coords

        self.properties.update({
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size-6,
                "family": font_family,
                "textAlign": text_align
            },
            "text": text,
            "foreColor": color
        })
        # if single line
        # self.text = self.create_text(0,0, font = font, fill=color)
        self.text_entry = tk.Entry(self.text_frame, font=font, fg=color, width=self.width,
                                   show=self.password_char, state='readonly' if self.read_only else "normal", textvariable=self.entry_value)
        self.text_entry.place(width=self.width, height=self.height)
        self.set_text(text)

    def set_text(self, text):
        self.text_entry.delete(0, tk.END)
        self.text_entry.insert(0, text)

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "textFont":
                if sub_property == "textAlign":
                    pass
                    # coords_text, anchor_text = calculate_coords(self, self.btn_text,
                    #                                             value, self.properties["width"], self.properties["height"])
                    # self.moveto(self.btn_text, int(
                    #     coords_text[0]), int(coords_text[1]))
                    # self.itemconfigure(self.btn_text, anchor=anchor_text)
                    # self.moveto(self.btn_text, int(
                    #     coords_text[0]), int(coords_text[1]))
                    # self.itemconfigure(self.btn_text, anchor=anchor_text)
                else:
                    font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                                weight=NORMAL if not self.properties[property_name]["bold"] else BOLD, slant=ROMAN if not self.properties[property_name]["italic"] else ITALIC)
                    self.text_entry.configure(font=font)
        else:
            if property_name == "width":
                self.configure(width=value)
                self.text_frame.configure(width=value)
            elif property_name == "height":
                self.text_frame.configure(height=value)
                self.configure(height=value)
            elif property_name == "backColor":
                self.text_frame.configure(bg=value)
                self.text_entry.configure(bg=value)
                self.configure(bg=value)
            elif property_name == "posX":
                self.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.place(x=self.properties["posX"], y=value)
            elif property_name == "text":
                self.set_text(value)
                # self.itemconfig(self.btn_text, text=value)
            elif property_name == "foreColor":
                self.text_entry.configure(fg=value)
                # self.itemconfig(self.btn_text, fill=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            if property_name == "text":
                return self.entry_value.get()
            return self.properties[property_name]


class CompiledLabel(tk.Canvas):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height):
        self.btn_frame = tk.Frame(win)
        super(CompiledLabel, self).__init__(self.btn_frame)
        self.id = id
        self.btn_frame.config(bg=back_color)
        self.btn_frame.place(x=pos_x, y=pos_y, width=width, height=height)
        self.configure(bg=back_color, width=width,
                       height=height, relief=tk.SUNKEN)
        self.pack()
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "backColor": back_color,
            "posX": pos_x,
            "posY": pos_y,
            "image": {
                "enabled": False,
                "imageName": "",
                "imageAlign": "",
                "width": width,
                "height": height
            },
            "textFont": {
                "bold": False,
                "italic": False,
                "size": 12,
                "family": "Arial",
                "textAlign": ""
            },
            "text": "",
            "foreColor": "#000000"
        }
        self.btn_img = self.create_image(0, 0)
        self.btn_text = self.create_text(0, 0)

    def display_text(self, text, coords, font_family, font_size, color, is_bold, is_italic, anchor=tk.CENTER, text_align="MiddleCenter"):
        font = Font(family=font_family, size=font_size-6,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        pos_x, pos_y = coords
        self.properties.update({
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size-6,
                "family": font_family,
                "textAlign": text_align
            },
            "text": text,
            "foreColor": color
        })
        self.moveto(self.btn_text, pos_x, pos_y)
        self.itemconfigure(self.btn_text,
                           anchor=anchor, text=text, fill=color, font=font)
        self.set_property("textFont/textAlign", text_align)

    def display_image(self, img_name, width, height, coords, anchor=tk.CENTER, image_align="MiddleRight"):
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.image_tk = ImageTk.PhotoImage(image)
        pos_x, pos_y = coords
        self.properties.update({
            "image": {
                "enabled": True,
                "imageName": img_name,
                "imageAlign": image_align,
                "width": width,
                "height": height
            }
        })
        self.moveto(self.btn_img, pos_x, pos_y)
        self.itemconfigure(self.btn_img, anchor=anchor, image=self.image_tk)
        self.set_property("image/imageAlign", image_align)

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "image":
                if sub_property == "enabled":
                    if not value:
                        self.itemconfigure(self.btn_img, state="hidden")
                    else:
                        self.itemconfigure(self.btn_img, state="normal")
                elif sub_property == "imageAlign":
                    coords_image, anchor_image = calculate_coords(self, None,
                                                                  value, self.properties[property_name]["width"], self.properties[property_name]["height"])
                    self.moveto(self.btn_img, coords_image[0], coords_image[1])
                    self.itemconfigure(self.btn_img, anchor=anchor_image)
                if self.properties[property_name]["enabled"]:
                    if sub_property == "imageName":
                        image = Image.open(os.path.join(RESOURCES_DIR, value))
                        image = image.resize(
                            (self.properties[property_name]["width"], self.properties[property_name]["height"]))
                    elif sub_property == "width":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (value, self.properties[property_name]["height"]))
                    elif sub_property == "height":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (self.properties[property_name]["width"], value))

                    self.image_tk = ImageTk.PhotoImage(image)
                    self.itemconfig(self.btn_img, image=self.image_tk)
            elif property_name == "textFont":
                if sub_property == "textAlign":
                    coords_text, anchor_text = calculate_coords(self, self.btn_text,
                                                                value, self.properties["width"], self.properties["height"])
                    self.moveto(self.btn_text, int(
                        coords_text[0]), int(coords_text[1]))
                    self.itemconfigure(self.btn_text, anchor=anchor_text)
                    self.moveto(self.btn_text, int(
                        coords_text[0]), int(coords_text[1]))
                    self.itemconfigure(self.btn_text, anchor=anchor_text)
                else:
                    font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                                weight=NORMAL if not self.properties[property_name]["bold"] else BOLD, slant=ROMAN if not self.properties[property_name]["italic"] else ITALIC)
                    self.itemconfigure(self.btn_text, font=font)
        else:
            if property_name == "width":
                self.btn_frame.configure(width=value)
                self.configure(width=value)
            elif property_name == "height":
                self.btn_frame.configure(height=value)
                self.configure(height=value)
            elif property_name == "backColor":
                self.btn_frame.configure(bg=value)
                self.configure(bg=value)
            elif property_name == "posX":
                self.btn_frame.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.btn_frame.place(x=self.properties["posX"], y=value)
            elif property_name == "text":
                self.itemconfig(self.btn_text, text=str(value))
            elif property_name == "foreColor":
                self.itemconfig(self.btn_text, fill=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledCheckBox(tk.Canvas):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height, check_state, checked):

        super(CompiledCheckBox, self).__init__(win)
        self.id = id
        self.check_frame = tk.Frame(self)
        self.check_frame.config(bg=back_color)
        self.configure(bg=back_color, width=width,
                       height=height, relief=tk.SUNKEN)
        self.place(x=pos_x, y=pos_y)
        self.check_frame.place(x=1, y=1, width=width, height=height)
        self.checked = checked
        self.check_state = check_state
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "backColor": back_color,
            "posX": pos_x,
            "posY": pos_y,
            "checkState": self.check_state,
            "checked": self.checked,
            "image": {
                "enabled": False,
                "imageName": "",
                "imageAlign": "",
                "width": width,
                "height": height
            },
            "background": False,
            "bgImageName": "",
            "textFont": {
                "bold": False,
                "italic": False,
                "size": 12,
                "family": "Arial",
                "textAlign": ""
            },
            "text": "",
            "foreColor": "#000000"
        }
        self.bg_image = self.create_image(0, 0)
        self.btn_img = self.create_image(0, 0)

    def display_checkbox(self, text, coords, font_family, font_size, color, is_bold, is_italic, anchor=tk.CENTER, text_align="MiddleCenter"):
        font = Font(family=font_family, size=font_size,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        pos_x, pos_y = coords
        self.value = tk.BooleanVar(value=self.checked)
        self.checkbox = tk.Checkbutton(
            self.check_frame, text=text, variable=self.value, font=font, fg=color, anchor=anchor)
        self.checkbox.pack(side=tk.LEFT, fill=tk.BOTH, anchor=anchor)
        self.properties.update({
            "text": text,
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size,
                "family": font_family,
                "textAlign": text_align
            }
        })
        # self.btn_text = self.create_text(
        #     pos_x, pos_y, anchor=anchor, text=text, fill=color, font=font)

    def display_image(self, img_name, width, height, coords, anchor=tk.CENTER, image_align="MiddleCenter"):
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.image_tk = ImageTk.PhotoImage(image)
        pos_x, pos_y = coords
        self.properties.update({
            "image": {
                "enabled": True,
                "imageName": img_name,
                "imageAlign": image_align,
                "width": width,
                "height": height
            }
        })
        self.moveto(self.btn_img, pos_x, pos_y)
        self.itemconfigure(self.btn_img, anchor=anchor, image=self.image_tk)

    def display_bg_image(self, img_name, width, height):
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.bg_image_tk = ImageTk.PhotoImage(image)
        self.properties.update({
            "background": True,
            "bgImageName": img_name
        })
        self.moveto(self.bg_image, width/2, height/2)
        self.itemconfigure(self.bg_image, image=self.image_tk)

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "image":
                if sub_property == "enabled":
                    if not value:
                        self.itemconfigure(self.btn_img, state="hidden")
                    else:
                        self.itemconfigure(self.btn_img, state="normal")
                elif sub_property == "imageAlign":
                    coords_image, anchor_image = calculate_coords(self, None,
                                                                  value, self.properties[property_name]["width"], self.properties[property_name]["height"])
                    self.moveto(self.btn_img, coords_image[0], coords_image[1])
                    self.itemconfigure(self.btn_img, anchor=anchor_image)
                if self.properties[property_name]["enabled"]:
                    if sub_property == "imageName":
                        image = Image.open(os.path.join(RESOURCES_DIR, value))
                        image = image.resize(
                            (self.properties[property_name]["width"], self.properties[property_name]["height"]))
                    elif sub_property == "width":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (value, self.properties[property_name]["height"]))
                    elif sub_property == "height":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (self.properties[property_name]["width"], value))

                    self.image_tk = ImageTk.PhotoImage(image)
                    self.itemconfig(self.btn_img, image=self.image_tk)
            elif property_name == "textFont":
                if sub_property == "textAlign":
                    coords_text, anchor_text = calculate_coords(self, self.btn_text,
                                                                value, self.properties["width"], self.properties["height"])
                    self.moveto(self.btn_text, int(
                        coords_text[0]), int(coords_text[1]))
                    self.itemconfigure(self.btn_text, anchor=anchor_text)
                    self.moveto(self.btn_text, int(
                        coords_text[0]), int(coords_text[1]))
                    self.itemconfigure(self.btn_text, anchor=anchor_text)
                else:
                    font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                                weight=NORMAL if not self.properties[property_name]["bold"] else BOLD, slant=ROMAN if not self.properties[property_name]["italic"] else ITALIC)
                    self.itemconfigure(self.btn_text, font=font)
        else:
            if property_name == "width":
                self.btn_frame.configure(width=value)
                self.configure(width=value)
            elif property_name == "height":
                self.btn_frame.configure(height=value)
                self.configure(height=value)
            elif property_name == "backColor":
                self.btn_frame.configure(bg=value)
                self.configure(bg=value)
                self.checkbox.configure(bg=value)
            elif property_name == "posX":
                self.btn_frame.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.btn_frame.place(x=self.properties["posX"], y=value)
            elif property_name == "text":
                self.checkbox.configure(text=value)
                # self.itemconfig(self.btn_text, text=value)
            elif property_name == "foreColor":
                self.checkbox.configure(fg=value)
                # self.itemconfig(self.btn_text, fill=value)
            elif property_name == "checked":
                self.value.set(value)
            elif property_name == "background":
                if value:
                    self.itemconfigure(self.bg_image, state="normal")
                else:
                    self.itemconfigure(self.bg_image, state="hidden")
            elif property_name == "bgImageName":
                image = Image.open(os.path.join(RESOURCES_DIR, value))
                image = image.resize(
                    (self.properties["width"], self.properties["height"]))
                self.bg_image_tk = ImageTk.PhotoImage(image)
                self.itemconfigure(self.bg_image, image=self.image_tk)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            if property_name == "checked":
                return self.value.get()
            return self.properties[property_name]


class CompiledRadioGroup(tk.Canvas):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height, checked_btn):

        super(CompiledRadioGroup, self).__init__(win)
        self.id = id
        self.check_frame = tk.Frame(self)
        self.check_frame.connfig(bg=back_color)
        self.configure(bg=back_color, width=width,
                       height=height, relief=tk.SUNKEN)
        self.place(x=pos_x, y=pos_y)
        self.check_frame.place(x=1, y=1, width=width, height=height)
        self.value = tk.IntVar()
        self.value.set(checked_btn)
        self.radiobuttons = []
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "backColor": back_color,
            "posX": pos_x,
            "posY": pos_y,
            "checkedBtn": 0,
            "image": {
                "enabled": False,
                "imageName": "",
                "imageAlign": "",
                "width": width,
                "height": height
            },
            "background": False,
            "bgImageName": "",
            "textFont": {
                "bold": False,
                "italic": False,
                "size": 12,
                "family": "Arial",
                "textAlign": ""
            },
            "text": "",
            "foreColor": "#000000",
            "group": []
        }
        self.bg_image = self.create_image(0, 0)
        self.btn_img = self.create_image(0, 0)

    def display_radiobutton(self, val, text, coords, font_family, font_size, color, is_bold, is_italic, anchor=tk.CENTER):
        font = Font(family=font_family, size=font_size,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        pos_x, pos_y = coords
        # self.value = tk.BooleanVar(value=self.checked)
        radiobutton = tk.Radiobutton(self.check_frame,
                                     text=text,
                                     padx=20,
                                     variable=self.value,
                                     font=font,
                                     fg=color,
                                     bg=self.properties["backColor"],
                                     #    command=ShowChoice,
                                     value=val)
        # self.checkbox = tk.Checkbutton(
        #     self.check_frame, text=text, variable=self.value, font=font, fg=color, anchor=anchor)
        radiobutton.pack(anchor=anchor)
        # self.btn_text = self.create_text(
        #     pos_x, pos_y, anchor=anchor, text=text, fill=color, font=font)
        self.radiobuttons.append(radiobutton)
        self.properties["group"].append({
            "text": text
        })

    def display_image(self, img_name, width, height, coords, anchor=tk.CENTER, image_align="MiddleCenter"):
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.image_tk = ImageTk.PhotoImage(image)
        pos_x, pos_y = coords
        # self.btn_img = self.create_image(
        #     pos_x, pos_y, anchor=anchor, image=self.image_tk)
        self.properties.update({
            "image": {
                "enabled": True,
                "imageName": img_name,
                "imageAlign": image_align,
                "width": width,
                "height": height
            }
        })
        self.moveto(self.btn_img, pos_x, pos_y)
        self.itemconfigure(self.btn_img, anchor=anchor, image=self.image_tk)

    def display_bg_image(self, img_name, width, height):
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.bg_image_tk = ImageTk.PhotoImage(image)
        # self.create_image(width/2, height/2, image=self.bg_image_tk)
        self.properties.update({
            "background": True,
            "bgImageName": img_name
        })
        self.moveto(self.bg_image, width/2, height/2)
        self.itemconfigure(self.bg_image, image=self.image_tk)

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "image":
                if sub_property == "enabled":
                    if not value:
                        self.itemconfigure(self.btn_img, state="hidden")
                    else:
                        self.itemconfigure(self.btn_img, state="normal")
                elif sub_property == "imageAlign":
                    coords_image, anchor_image = calculate_coords(self, None,
                                                                  value, self.properties[property_name]["width"], self.properties[property_name]["height"])
                    self.moveto(self.btn_img, coords_image[0], coords_image[1])
                    self.itemconfigure(self.btn_img, anchor=anchor_image)
                if self.properties[property_name]["enabled"]:
                    if sub_property == "imageName":
                        image = Image.open(os.path.join(RESOURCES_DIR, value))
                        image = image.resize(
                            (self.properties[property_name]["width"], self.properties[property_name]["height"]))
                    elif sub_property == "width":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (value, self.properties[property_name]["height"]))
                    elif sub_property == "height":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (self.properties[property_name]["width"], value))

                    self.image_tk = ImageTk.PhotoImage(image)
                    self.itemconfig(self.btn_img, image=self.image_tk)
            elif property_name == "textFont":
                if sub_property == "textAlign":
                    pass
                    # coords_text, anchor_text = calculate_coords(self, self.btn_text,
                    # value, self.properties["width"], self.properties["height"])
                    # self.moveto(self.btn_text, int(
                    #     coords_text[0]), int(coords_text[1]))
                    # self.itemconfigure(self.btn_text, anchor=anchor_text)
                    # self.moveto(self.btn_text, int(
                    #     coords_text[0]), int(coords_text[1]))
                    # self.itemconfigure(self.btn_text, anchor=anchor_text)
                else:
                    font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                                weight=NORMAL if not self.properties[property_name]["bold"] else BOLD, slant=ROMAN if not self.properties[property_name]["italic"] else ITALIC)
                    for radio_btn in self.radiobuttons:
                        radio_btn.configure(font=font)
                    # self.itemconfigure(self.btn_text, font=font)
        else:
            if property_name == "width":
                self.btn_frame.configure(width=value)
                self.configure(width=value)
            elif property_name == "height":
                self.btn_frame.configure(height=value)
                self.configure(height=value)
            elif property_name == "backColor":
                self.btn_frame.configure(bg=value)
                self.configure(bg=value)
                for radio_btn in self.radiobuttons:
                    radio_btn.configure(bg=value)
            elif property_name == "posX":
                self.btn_frame.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.btn_frame.place(x=self.properties["posX"], y=value)
            # elif property_name == "text":
            #     self.itemconfig(self.btn_text, text=value)
            elif property_name == "foreColor":
                for radio_btn in self.radiobuttons:
                    radio_btn.configure(fg=value)
                # self.itemconfig(self.btn_text, fill=value)
            elif property_name == "checkedBtn":
                self.value.set(value)
            elif property_name == "background":
                if value:
                    self.itemconfigure(self.bg_image, state="normal")
                else:
                    self.itemconfigure(self.bg_image, state="hidden")
            elif property_name == "bgImageName":
                image = Image.open(os.path.join(RESOURCES_DIR, value))
                image = image.resize(
                    (self.properties["width"], self.properties["height"]))
                self.bg_image_tk = ImageTk.PhotoImage(image)
                self.itemconfigure(self.bg_image, image=self.image_tk)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            if property_name == "checkedBtn":
                return self.value.get()
            return self.properties[property_name]


class CompiledProgressBar(ttk.Progressbar):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height):
        super(CompiledProgressBar, self).__init__(win)
        self.id = id
        self.back_color = back_color
        self.place(x=pos_x, y=pos_y)
        self.width = width
        self.height = height
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "backColor": back_color,
            "posX": pos_x,
            "posY": pos_y,
            "foreColor": "#000000"
        }

    def display_progressbar(self, fore_color, minimum_val, maximum_val, step, value):
        s = ttk.Style()
        s.theme_use('alt')
        s.configure("{}.Horizontal.TProgressbar".format(self.id),
                    troughcolor=self.back_color, background=fore_color)
        self.configure(orient='horizontal', mode='indeterminate', length=self.width, value=value,
                       maximum=maximum_val, style="{}.Horizontal.TProgressbar".format(self.id))
        self.properties.update({
            "foreColor": fore_color,
            "minimum": minimum_val,
            "maximum": maximum_val,
            "step": step,
            "value": value
        })

    def process_set_property(self, property_name, value, sub_property=None):

        if property_name == "width":
            # self.btn_frame.configure(width=value)
            self.configure(length=value)
        elif property_name == "height":
            pass
            # self.btn_frame.configure(height=value)
            # self.configure(height=value)
        elif property_name == "backColor":
            s = ttk.Style()
            s.theme_use('alt')
            s.configure("{}.Horizontal.TProgressbar".format(self.id),
                        troughcolor=value, background=self.properties["foreColor"])
            self.configure(style="{}.Horizontal.TProgressbar".format(self.id))
        elif property_name == "posX":
            self.place(x=value, y=self.properties["posY"])
        elif property_name == "posY":
            self.place(x=self.properties["posX"], y=value)
            # self.itemconfig(self.btn_text, text=value)
        elif property_name == "maximum":
            self.configure(maximum=value)
        elif property_name == "value":
            self.configure(value=value)

        elif property_name == "foreColor":
            s = ttk.Style()
            s.theme_use('alt')
            s.configure("{}.Horizontal.TProgressbar".format(self.id),
                        troughcolor=self.properties["backColor"], background=value)
            self.configure(style="{}.Horizontal.TProgressbar".format(self.id))
            # self.itemconfig(self.btn_text, fill=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledPanel(tk.Frame):
    def __init__(self,  win, id, back_color, pos_x, pos_y, width, height):
        super(CompiledPanel, self).__init__(win, bg=back_color)
        self.configure(bg=back_color, width=width, height=height)
        self.id = id
        self.place(x=pos_x, y=pos_y, width=width, height=height)
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "posX": pos_x,
            "posY": pos_y,
            "backColor": back_color
        }

    def process_set_property(self, property_name, value, sub_property=None):
        if property_name == "width":
            self.configure(width=value)
        elif property_name == "height":
            self.configure(height=value)
        elif property_name == "posX":
            self.place(x=value, y=self.properties["posY"])
        elif property_name == "posY":
            self.place(x=self.properties["posX"], y=value)
        elif property_name == "backColor":
            self.configure(bg=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledCalendar(Calendar):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height, year, month, day, customFormat):
        self.frame = tk.Frame(win)
        self.frame.place(x=pos_x, y=pos_y, width=width, height=height)
        super(CompiledCalendar, self).__init__(
            self.frame, year=year, month=month, day=day)
        self.id = id
        self.back_color = back_color
        self.pack()
        self.time_frame = tk.Frame(self.frame)
        self.time_frame.pack()
        self.hour_string = tk.StringVar()
        self.min_string = tk.StringVar()
        self.sec_string = tk.StringVar()
        time_frame_inputs = tk.Frame(self.time_frame)
        time_frame_inputs.pack()
        self.hour_sb = tk.Spinbox(
            time_frame_inputs,
            from_=0,
            to=23,
            wrap=True,
            textvariable=self.hour_string,
            width=2,
            state="readonly",
            justify=tk.CENTER
        )
        self.min_sb = tk.Spinbox(
            time_frame_inputs,
            from_=0,
            to=59,
            wrap=True,
            textvariable=self.min_string,
            width=2,
            justify=tk.CENTER
        )

        self.sec_sb = tk.Spinbox(
            time_frame_inputs,
            from_=0,
            to=59,
            wrap=True,
            textvariable=self.sec_string,
            width=2,
            justify=tk.CENTER
        )
        self.hour_sb.pack(side=tk.LEFT, expand=2)
        self.min_sb.pack(side=tk.LEFT, expand=2)
        self.sec_sb.pack(side=tk.LEFT, expand=2)
        # self.configure(width=width, height=height)
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "posX": pos_x,
            "posY": pos_y,
            "backColor": back_color,
            "customFormat": customFormat.replace('MM', '%m').replace('DD', '%d').replace('yyyy', '%Y').replace('hh', '%H').replace('mm', '%M').replace('ss', '%S')
        }

    def display_calendar(self, font_family, font_size, is_bold, is_italic, fore_color, min_date, max_date, hour, minute, second):
        font = Font(family=font_family, size=font_size,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        min_date = datetime.strptime(min_date, '%d/%m/%Y')
        max_date = datetime.strptime(max_date, '%d/%m/%Y')
        self.configure(font=font, selectmode='day', locale='en_US',
                       mindate=min_date, maxdate=max_date, disabledforeground='red',
                       cursor="hand1",)
        self.hour_sb.config(font=font)
        self.min_sb.config(font=font)
        self.sec_sb.config(font=font)
        self.hour_string.set(int(hour))
        self.min_string.set(int(minute))
        self.sec_string.set(int(second))
        date_value = datetime.strftime(self.get_date(), '%m/%d/%y')
        date_time_str = date_value + ' {}:{}'.format(hour, minute)
        self.properties.update({
            "minDate": min_date,
            "maxDate": max_date,
            "value": date_time_str,
            "foreColor": fore_color,
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size,
                "family": font_family
            }
        })

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "textFont":
                font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                            weight=self.properties[property_name]["bold"], slant=self.properties[property_name]["italic"])
                self.configure(font=font)
        else:
            if property_name == "width":
                self.frame.configure(width=value)
            elif property_name == "height":
                self.frame.configure(height=value)
            elif property_name == "posX":
                self.frame.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.frame.place(x=self.properties["posX"], y=value)
            # elif property_name == "textAlign":
            #     self.configure(justify=value)
            elif property_name == "value":
                pass
                # self.var.set(tk.Variable(value=value))
                # self.configure(listvariables=tk.Variable(value=value))
                # self.configure(value=value)
            elif property_name == "backColor":
                self.configure(bg=value)
            elif property_name == "foreColor":
                self.configure(fg=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledTableLayout(ttk.Treeview):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height):
        super(CompiledTableLayout, self).__init__(win)
        self.place(x=pos_x, y=pos_y, width=width, height=height)
        self.properties = {
            "id": id,
            "width": width,
            "height": height,
            "posX": pos_x,
            "posY": pos_y,
            "backColor": back_color,
            "columns": [],
            "rows": []
        }

    def configure_columns(self, column_headers):
        self['columns'] = column_headers
        self.column("#0", width=0,  stretch=tk.NO)
        self.heading("#0", text="", anchor=tk.CENTER)

    def add_column(self, name, text, width, justify):
        self.column(name, anchor=justify, width=width)
        self.heading(name, text=text, anchor=justify)
        self.properties["columns"].append({
            "name": name,
            "text": text,
            "justify": justify,
            "width": width
        })

    def add_row(self, values, font_family, font_size, is_bold, is_italic, fore_color):
        font = Font(family=font_family, size=font_size,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        self.insert(parent='', index='end', text='', values=values, font=font,
                    foreground=fore_color, background=self.properties["backColor"])
        self.properties.update({
            "foreColor": fore_color,
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size,
                "family": font_family
            }
        })
        self.properties["rows"].append(values)

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "textFont":
                font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                            weight=self.properties[property_name]["bold"], slant=self.properties[property_name]["italic"])
                self.configure(font=font)
        else:
            if property_name == "width":
                self.list_frame.configure(width=value)
            elif property_name == "height":
                self.list_frame.configure(height=value)
            elif property_name == "posX":
                self.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.place(x=self.properties["posX"], y=value)
            # elif property_name == "textAlign":
            #     self.configure(justify=value)
            elif property_name == "value":
                # self.var.set(tk.Variable(value=value))
                self.configure(listvariables=tk.Variable(value=value))
                # self.configure(value=value)
            elif property_name == "backColor":
                self.configure(bg=value)
            elif property_name == "foreColor":
                self.configure(fg=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledListbox(tk.Listbox):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height):
        self.list_frame = tk.Frame(win)
        self.list_frame.place(x=pos_x, y=pos_y, width=width, height=height)
        self.frame = tk.Frame(self.list_frame)
        self.frame.pack(expand=True, fill='both')
        self.frame.pack_propagate(0)
        super(CompiledListbox, self).__init__(self.frame)
        self.id = id
        self.configure(bg=back_color)
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "posX": pos_x,
            "posY": pos_y,
            "backColor": back_color
        }

    def display_listbox(self, values, font_family, font_size, is_bold, is_italic, fore_color):
        font = Font(family=font_family, size=font_size,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        self.var = tk.Variable(value=values)
        self.scrollbar = ttk.Scrollbar(
            self.frame,
            orient=tk.VERTICAL,
            command=self.yview
        )
        self.configure(listvariable=self.var, font=font,
                       yscrollcommand=self.scrollbar.set, fg=fore_color)
        self.scrollbar.pack(side=tk.RIGHT, fill=tk.BOTH)
        self.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.properties.update({
            "foreColor": fore_color,
            "value": values,
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size,
                "family": font_family
            }
        })

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "textFont":
                font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                            weight=self.properties[property_name]["bold"], slant=self.properties[property_name]["italic"])
                self.configure(font=font)
        else:
            if property_name == "width":
                self.list_frame.configure(width=value)
            elif property_name == "height":
                self.list_frame.configure(height=value)
            elif property_name == "posX":
                self.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.place(x=self.properties["posX"], y=value)
            # elif property_name == "textAlign":
            #     self.configure(justify=value)
            elif property_name == "value":
                # self.var.set(tk.Variable(value=value))
                self.configure(listvariables=tk.Variable(value=value))
                # self.configure(value=value)
            elif property_name == "backColor":
                self.configure(bg=value)
            elif property_name == "foreColor":
                self.configure(fg=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledColorPicker:
    def __init__(self, win):
        self.win = win

    def show(self):
        self.color_chosen = askcolor((255, 255, 0), self.win)

    def get_property(self, property_name):
        self.show()
        return self.color_chosen


class CompiledCombobox(ttk.Combobox):
    def __init__(self, win, id, pos_x, pos_y, width, height):
        self.selected_value = tk.StringVar()
        super(CompiledCombobox, self).__init__(
            win, textvariable=self.selected_value)
        self.id = id
        self.place(x=pos_x, y=pos_y, width=width, height=height)
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "posX": pos_x,
            "posY": pos_y,
        }

    def display_combobox(self, font_family, font_size, is_bold, is_italic,  values, state, text_align):
        font = Font(family=font_family, size=font_size,
                    weight=NORMAL if not is_bold else BOLD, slant=ROMAN if not is_italic else ITALIC)
        self.configure(values=values, font=font, state=state)
        self.properties.update({
            "state": state,
            "value": values,
            "textFont": {
                "bold": is_bold,
                "italic": is_italic,
                "size": font_size,
                "family": font_family,
                "textAlign": text_align
            }
        })

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "textFont":
                font = Font(family=self.properties[property_name]["family"], size=self.properties[property_name]["size"],
                            weight=self.properties[property_name]["bold"], slant=self.properties[property_name]["italic"])
                self.configure(font=font)
        else:
            if property_name == "width":
                self.configure(width=value)
            elif property_name == "height":
                self.configure(height=value)
            elif property_name == "posX":
                self.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.place(x=self.properties["posX"], y=value)
            # elif property_name == "textAlign":
            #     self.configure(justify=value)
            elif property_name == "value":
                self.configure(values=value)
            elif property_name == "state":
                self.configure(state=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]


class CompiledNumericUpDown(tk.Spinbox):
    def __init__(self, win, id, back_color, fore_color, pos_x, pos_y, width, height):
        self.spin_frame = tk.Frame(win, height=height, width=width)
        self.spin_frame.place(x=pos_x, y=pos_y, height=height, width=width)
        self.value = tk.IntVar(self.spin_frame, value=0)
        super(CompiledNumericUpDown, self).__init__(self.spin_frame)
        self.id = id
        self.configure(bg=back_color, fg=fore_color, textvariable=self.value)
        self.width = width
        self.height = height
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "backColor": back_color,
            "posX": pos_x,
            "posY": pos_y,
            "foreColor": fore_color
        }

    def display_spinner(self, min, max, increment, text_align, up_down_align, value, separator):
        text_align = text_align.replace('top', '').replace(
            'bottom', '').replace('middle', '')
        self.configure(from_=min, to=max, justify=text_align, textvariable=self.value,
                       increment=increment)
        self.place(x=0, y=0, height=self.height, width=self.width)
        self.properties.update({
            "minimum": min,
            "maximum": max,
            "increment": increment,
            "textAlign": text_align,
            "value": value
        })

    def process_set_property(self, property_name, value, sub_property=None):

        if property_name == "width":
            self.spin_frame.configure(width=value)
            self.configure(width=value)
        elif property_name == "height":
            self.spin_frame.configure(height=value)
            self.configure(height=value)
        elif property_name == "backColor":

            self.configure(bg=value)
        elif property_name == "posX":
            self.spin_frame(x=value, y=self.properties["posY"])
        elif property_name == "posY":
            self.spin_frame(x=self.properties["posX"], y=value)
            # self.itemconfig(self.btn_text, text=value)
        elif property_name == "maximum":
            self.configure(to=value)
        elif property_name == "minimum":
            self.configure(from_=value)
        elif property_name == "textAlign":
            self.configure(justify=value)
        elif property_name == "increment":
            self.configure(increment=value)
        elif property_name == "value":
            self.value.set(value)
            # self.configure(value=value)

        elif property_name == "foreColor":
            self.configure(fg=value)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        elif property_name == 'value':
            return self.value.get()
        else:
            return self.properties[property_name]


class CompiledPictureBox(tk.Canvas):
    def __init__(self, win, id, back_color, pos_x, pos_y, width, height):
        self.btn_frame = tk.Frame(win)
        super(CompiledPictureBox, self).__init__(self.btn_frame)
        self.id = id
        self.btn_frame.config(bg=back_color)
        self.btn_frame.place(x=pos_x, y=pos_y, width=width, height=height)
        self.configure(bg=back_color, width=width,
                       height=height, relief=tk.SUNKEN)
        self.pack()
        self.properties = {
            "id": self.id,
            "width": width,
            "height": height,
            "backColor": back_color,
            "posX": pos_x,
            "posY": pos_y,
            "image": {
                "enabled": False,
                "imageName": "",
                "imageAlign": "",
                "width": width,
                "height": height
            },
            "background": False,
            "bgImageName": "",
        }
        self.bg_image = self.create_image(0, 0)
        self.btn_img = self.create_image(0, 0)

    def display_image(self, img_name, width, height, coords, anchor=tk.CENTER, image_align="MiddleCenter"):
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.image_tk = ImageTk.PhotoImage(image)
        pos_x, pos_y = coords
        self.properties.update({
            "image": {
                "enabled": True,
                "imageName": img_name,
                "imageAlign": image_align,
                "width": width,
                "height": height
            }
        })
        self.moveto(self.btn_img, pos_x, pos_y)
        self.itemconfigure(self.btn_img, anchor=anchor, image=self.image_tk)

    def display_bg_image(self, img_name, width, height):
        image = Image.open(os.path.join(RESOURCES_DIR, img_name))
        image = image.resize((width, height))
        self.bg_image_tk = ImageTk.PhotoImage(image)
        self.properties.update({
            "background": True,
            "bgImageName": img_name
        })
        self.moveto(self.bg_image, width/2, height/2)
        self.itemconfigure(self.bg_image, image=self.image_tk)

    def process_set_property(self, property_name, value, sub_property=None):
        if sub_property:
            if property_name == "image":
                if sub_property == "enabled":
                    if not value:
                        self.itemconfigure(self.btn_img, state="hidden")
                    else:
                        self.itemconfigure(self.btn_img, state="normal")
                elif sub_property == "imageAlign":
                    coords_image, anchor_image = calculate_coords(self, None,
                                                                  value, self.properties[property_name]["width"], self.properties[property_name]["height"])
                    self.moveto(self.btn_img, coords_image[0], coords_image[1])
                    self.itemconfigure(self.btn_img, anchor=anchor_image)
                if self.properties[property_name]["enabled"]:
                    if sub_property == "imageName":
                        image = Image.open(os.path.join(RESOURCES_DIR, value))
                        image = image.resize(
                            (self.properties[property_name]["width"], self.properties[property_name]["height"]))
                    elif sub_property == "width":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (value, self.properties[property_name]["height"]))
                    elif sub_property == "height":
                        image = Image.open(os.path.join(
                            RESOURCES_DIR, self.properties[property_name]["imageName"]))
                        image = image.resize(
                            (self.properties[property_name]["width"], value))

                    self.image_tk = ImageTk.PhotoImage(image)
                    self.itemconfig(self.btn_img, image=self.image_tk)
        else:
            if property_name == "width":
                self.btn_frame.configure(width=value)
                self.configure(width=value)
            elif property_name == "height":
                self.btn_frame.configure(height=value)
                self.configure(height=value)
            elif property_name == "backColor":
                self.btn_frame.configure(bg=value)
                self.configure(bg=value)
            elif property_name == "posX":
                self.btn_frame.place(x=value, y=self.properties["posY"])
            elif property_name == "posY":
                self.btn_frame.place(x=self.properties["posX"], y=value)
            elif property_name == "background":
                if value:
                    self.itemconfigure(self.bg_image, state="normal")
                else:
                    self.itemconfigure(self.bg_image, state="hidden")
            elif property_name == "bgImageName":
                image = Image.open(os.path.join(RESOURCES_DIR, value))
                image = image.resize(
                    (self.properties["width"], self.properties["height"]))
                self.bg_image_tk = ImageTk.PhotoImage(image)
                self.itemconfigure(self.bg_image, image=self.image_tk)

    def set_property(self, property_name, value):
        if property_name == "id":
            return
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            self.properties[parent_obj][child_obj] = value
            self.process_set_property(parent_obj, value, child_obj)
        else:
            self.properties[property_name] = value
            self.process_set_property(property_name, value)

    def get_property(self, property_name):
        if "/" in property_name:
            parent_obj, child_obj = property_name.split("/")
            return self.properties[parent_obj][child_obj]
        else:
            return self.properties[property_name]
