2
\$\begingroup\$

It's an inventory UI and also displays the player's stats. I have been programming for a year or more and I want to improve my code.

import Tkinter as tk
import copy



class InvBox:
    def __init__(self, world, party1data, extract_func, *arg, **kwarg):
        # data from world
        self.world = world  # world instance
        self.parent = world.parent
        self.cn = world.cn  # world canvas
        self.items = world.items  # world item data
        self.rsc = self.world.rsc  # world Gif image list
        self.p1data = party1data  # world party1 data
        self.extract = extract_func  # func before deleting this ui
        # start building the ui
        self.set_variables()
        self.set_ui()  # create basic ui
        self.update_ui()


    def set_variables(self, *args):
        # init stats and other variables
        self.wtag = self.world.mtag  # main tag of world
        self.mtag = "caUI"  # main tag of this ui
        # for hover stats
        self.hover_cooldown = False
        self.go = None
        self.glowing = None
        # fonts
        self.f1, self.fsz1 = "Book Antiqua", 12
        self.f2, self.fsz2 = "Segoe UI", 11
        self.f3, self.fsz3 = "Book Antiqua", 17
        self.font1 = ("Book Antiqua", 12)  # general
        self.font1b = ("Book Antiqua", 12, "bold")
        self.font2 = ("Segoe UI", 11)  # stats
        self.font2b = ("Segoe UI", 11, "bold")
        self.font3 = ("Book Antiqua", 17)  # buttons


    def set_ui(self, *args):  # ui skeleton
        self.mimg(400, 50, "inv_bg-635x485", anchor="n")
        self.mimg(400, 50, "inv_bgt-635x25", anchor="n")
        # creating party1 info panel
        X, Y = 109, 95  # starting nw coords of the partyl inv panel
        self.mimg(X, Y, "inv_bg1-280x105")
        self.mimg(X, Y, "ava_player-100x105", tags=("p1_ava"))  # default ava
        self.mtxt(X+105, Y+5, "Geralt of Rpivilon", font=self.font1b,
            tags=("p1_name", "p1_stats"))
        self.mrect(X+103, Y+27, 172, 22, "#851122", tags=("p1_hpbar_bg"))
        self.mrect(X+103, Y+27, 172, 22, "brown", tags=("p1_hpbar"))
        self.mtxt(X+105, Y+28, "HP:", font=self.font2, tags=("p1_statsn"))
        self.mtxt(X+272, Y+28, "0", font=self.font2,
            tags=("p1_hp", "p1_statsn"), anchor="ne")
        s = [["Atk:", "0"], ["Def:", "0"], ["D%:", "0"], ["AP:", "0"]]
        for i in range(2):
            for x in range(2):
                w = 84
                h = 22
                x1 = X + 103 + (i * 88)
                y1 = Y + 52 + (x * 25)
                n = x + (i * 2)
                txt = s[n][0][:-1]
                # create stat display
                self.mrect(x1, y1, w, h, "#851122", 
                    tags=("p1_{}bar_bg".format(txt)))
                self.mrect(x1, y1, w, h, "brown",
                    tags=("p1_{}bar".format(txt)))
                self.mtxt(x1 + 2, y1 + 1, s[n][0],
                    font=self.font2, tags=("p1_statsn"))
                self.mtxt(x1 + w - 3, y1 + 1, s[n][1], 
                    font=self.font2, anchor="ne",
                    tags=("p1_{}".format(txt), "p1_statsn"))
        # creating party1 equipped items and other stats
        X1, Y1 = 109, 205  # starting nw coords
        self.mimg(X1, Y1, "bg_inv-280x306")
        self.mimg(X1+65, Y1+17, "img_player-150x200", "p1_img")
        b = ["helmet", "armor", "boots", "ring", "weapon", "trinket"]
        for i in range(2):  # 2x3 item slots
            for x1 in range(3):
                n = x1 + (i * 3)
                x = X1 + 18 + (i * 199)
                y = Y1 + 14 + (x1 * 77)
                tag = "p1_{}".format(b[n])
                self.mimg(x, y, "aInv_e{}0".format(b[n].capitalize()),
                    tags=(tag, "equipped_imgs"))
                # apply unequip function
                self.cn.tag_bind(self.m(tag), "<Enter>",
                    lambda _, x=x, y=y, n=n: self.hoverstats_inv(0, x, y, n))
                self.cn.tag_bind(self.m(tag), "<Leave>",
                    self.hoverstats_inv_fade)
        self.mrect(X1+67, Y1+222, 146, 15, "#851122", tags=("p1_expbar_bg"))
        self.mrect(X1+67, Y1+222, 73, 15, "brown", tags=("p1_expbar"))
        c = [
            ["Scn:", "0"], ["Exp:", "1"], ["H%:", "2"],
            ["IA%:", "3"], ["C%:", "4"], ["Cd%:", "5"]
        ]
        for i in range(3):
            for x in range(2):
                w = 84  # width
                h = 22  # height
                x1 = X1 + 5 + (i * (w + 4))
                y1 = Y1 + 251 + (x * (h + 3))
                b = 10
                n = x + (i * 2)
                txt = c[n][0][:-1]
                x1 += 0 if i == 0 else b  # make space due to rect increase
                w += b if i == 0 else 0  # increase size of rect
                # create stat display
                self.mrect(x1, y1, w, h, "#851122", 
                    tags=("p1_{}bar_bg".format(txt)))
                self.mrect(x1, y1, w, h, "brown",
                    tags=("p1_{}bar".format(txt)))
                self.mtxt(x1 + 2, y1 + 1, c[n][0],
                    font=self.font2, tags=("p1_statsn"))
                self.mtxt(x1 + w - 3, y1 + 1, c[n][1],
                    font=self.font2, anchor="ne",
                    tags=("p1_{}".format(txt), "p1_statsn"))
        # creating place holder img with leave button
        X2, Y2 = 412, 95
        self.mimg(X2, Y2, "inv_bg1-280x105")
        self.mimg(X2+6, Y2+8, "aInv_bg0-220x90")
        self.mimg(X2+229, Y2+15, "img_button2", tags=("leave_btn",))
        # creating party1 inventory
        X3, Y3 = 412, 205
        w, h = 2, 2  # distance between images
        for row in range(4):
            for col in range(6):
                n = col + (row * 6)
                x = X3 + (col * (45 + w))
                y = Y3 + (row * (75 + h))
                tag = "p1_inv{}".format(n)
                self.mimg(x, y, "inv_empty-45x75", tags=(tag,))  # tuple
                # apply equip function
                self.cn.tag_bind(self.m(tag), "<Enter>",
                    lambda _, x=x, y=y, n=n: self.hoverstats_inv(1, x, y, n))
                self.cn.tag_bind(self.m(tag), "<Leave>",
                    self.hoverstats_inv_fade)


    def update_ui(self, *args):
        def m(tags):
            return self.m(tags)
        p1 = self.p1data
        X, Y = 109, 95  # starting nw coords of the partyl inv panel
        X1, Y1 = 109, 205  # starting nw coords party1 equipped items
        self.cn.itemconfigure(m("p1_name"), text=p1["name"])
        self.cn.itemconfigure(m("p1_ava"), image=self.rsc[p1["avatar"]])
        self.cn.delete(m("p1_hpbar"))
        l = 172.0 * (p1["stats"][0][0] / float(p1["stats"][0][1]))
        self.mrect(X+103, Y+27, l, 22, "brown", tags=("p1_hpbar"))
        txt = "{}/{}".format(p1["stats"][0][0], p1["stats"][0][1])
        self.cn.itemconfigure(m("p1_hp"), text=txt)
        self.cn.itemconfigure(m("p1_img"), image=self.rsc[p1["image"]])
        s = [["Atk:", "0"], ["Def:", "0"], ["D%:", "0"], ["AP:", "0"]]
        s1 = [p1["stats"][4], p1["stats"][3], p1["stats"][2], p1["stats"][1]]
        maxn = [50, 50, 100, 10]
        for i in range(2):
            for x in range(2):
                w = 84
                h = 22
                x1 = X + 103 + (i * 88)
                y1 = Y + 52 + (x * 25)
                n = x + (i * 2)
                txt = s[n][0][:-1]
                tag0 = m("p1_{}".format(txt))
                tag1 = m("p1_{}bar".format(txt))
                # create stat display
                self.cn.itemconfigure(tag0, text=s1[n])
                self.cn.delete(tag1)
                max = maxn[n]
                l = float(w) * (s1[n] / float(max))
                self.mrect(x1, y1, l, h, "brown", tags=(tag1))
        e = p1["equipped"]
        b = ["helmet", "armor", "boots", "ring", "weapon", "trinket"]
        for i in range(len(e)):
            tag = "p1_{}".format(b[i])
            self.cn.itemconfigure(m(tag),
                image=self.rsc["aInv_e{}0".format(b[i].capitalize())])
            if e[i] != None:
                img = self.rsc[self.items[e[i]]["img"]]
                self.cn.itemconfigure(m(tag), image=img)
        self.cn.delete(m("p1_expbar"))
        l = 146.0 * (p1["stats"][5] % 1000 / 1000.0)
        self.mrect(X1+67, Y1+222, l, 15, "brown", tags=("p1_expbar"))
        c = [
            ["Scn:", "0"], ["Exp:", "1"], ["H%:", "2"],
            ["IA%:", "3"], ["C%:", "4"], ["Cd%:", "5"]
        ]
        c1 = [
            p1["coin"], p1["stats"][5], p1["stats"][6],
            p1["stats"][7], p1["stats"][8], p1["stats"][9]
        ]
        for i in range(3):
            for x in range(2):
                w = 84  # width
                h = 22  # height
                x1 = X1 + 5 + (i * (w + 4))
                y1 = Y1 + 251 + (x * (h + 3))
                b = 10
                n = x + (i * 2)
                txt = c[n][0][:-1]
                x1 += 0 if i == 0 else b  # make space due to rect increase
                w += b if i == 0 else 0  # increase size of rect
                tag0 = m("p1_{}".format(txt))
                tag1 = m("p1_{}bar".format(txt))
                # config stat display
                self.cn.itemconfigure(tag0, text=c1[n])
                if n < 2:
                    continue  # skip below, next iteration
                self.cn.delete(tag1)
                max = 100 if n < 5 else 1000
                l = float(w) * (c1[n] / float(max))
                self.mrect(x1, y1, l, h, "brown", tags=(tag1))
        p1_inv = p1["inventory"] + ["empty"] * (24 - len(p1["inventory"]))
        for row in range(4):
            for col in range(6):
                n = col + (row * 6)
                tag = m("p1_inv{}".format(n))
                if p1_inv[n] != "empty":
                    self.cn.itemconfigure(tag,
                        image=self.rsc[self.items[p1_inv[n]]["img"]])
        # make stats visible
        self.cn.tag_raise(m("p1_statsn"))
        self.cn.tag_raise(m("equipped_imgs"))


    def hoverstats_inv_fade(self, *args):
        if self.go is not None:
            self.parent.after_cancel(self.go)
            self.go = None
        self.cn.delete(self.m("hover_stats"))


    def hoverstats_inv(self, invn, x, y, item_index, stage=0, *args):
        # separate to prevent crashing, crashes after
        # called multiple times instead of once
        self.cn.delete(self.m("hover_stats"))
        xn = (x + 47) if (x + 152) < 760 else (x-152)
        yn = y - 7
        invnm = "inventory"
        inv0 = self.p1data["equipped"]
        inv1 = self.p1data[invnm] + ["empty"] * (24 - len(self.p1data[invnm]))
        inv = [inv0, inv1]
        if inv[invn][item_index] != "empty" and inv[invn][item_index] != None:
            if stage == 0:
                self.hoverstats_inv_fade()
                self.go = self.parent.after(250,
                    lambda: self.hoverstats_inv(invn, x, y, item_index, stage=1))
            elif stage == 1:
                item_n = self.items[inv[invn][item_index]]["name"]
                item_t = self.items[inv[invn][item_index]]["type"]
                item_p = self.items[inv[invn][item_index]]["sell_price"]
                mtag = ("hover_stats",)
                self.mimg(xn, yn, image="bg-150x105", tags=mtag)
                self.mtxt(xn+5, yn+5, txt=item_n, font=self.font1b, tags=mtag)
                self.mtxt(xn+7, yn+22, txt=item_t, font=self.font2, tags=mtag)
                self.mtxt(xn+150-72, yn+102, txt="Scnr:", font=self.font1,
                    tags=mtag, anchor="se")
                self.mtxt(xn+150-5, yn+102, txt=item_p, font=self.font1,
                    tags=mtag, anchor="se")


    def m(self, tag):
        return "{}_{}".format(self.mtag, tag)


    def check_tags(self, tags):
        # Input: ("a", "b")
        # Output: (mtag, "mtag_a", "mtag_b")
        if tags is None:
            tags = self.mtag
        elif isinstance(tags, str):  # string
            tags = self.m(tags)
        else:
            x = []
            for i in tags:
                x.append(self.m(i))
            tags = tuple([self.mtag] + x)
        return tags


    def mrect(self, x1, y1, w, h, fill="black", tags=None):
        tags = self.check_tags(tags)  # must be tuple
        self.cn.create_rectangle(x1, y1, x1+w, y1+h, fill=fill, tags=tags,
            outline="")


    def mimg(self, x, y, image, tags=None, anchor=tk.NW, *args):
        tags = self.check_tags(tags)  # must be tuple
        self.cn.create_image(x, y, image=self.rsc[image], tags=tags,
            anchor=anchor)


    def mtxt(self, x, y, txt, tags=None, font=None, anchor=tk.NW,
        fill="black", width=250, align="left", *args):
        tags = self.check_tags(tags)  # must be tuple
        font = (self.f1, self.fsz1) if font is None else font
        self.cn.create_text(x, y, text=txt, tags=tags, font=font,
            anchor=anchor, fill=fill, width=width, justify=align)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.