Ejemplo n.º 1
0
class DiceviewApp:
    class States(Enum):
        SAMPLE = 0
        SAMPLE_WAIT = 1
        SAMPLE_READY = 2

    PADDING = 5
    ROWMIN = 400
    COLMIN = 800

    FACES = 20

    def __init__(self):
        self.root = tkinter.Tk()
        self.root.title("diceview")
        try:
            self.root.state("zoomed")
        except (tkinter.TclError):
            pass
            m = self.root.maxsize()
            self.root.geometry('{}x{}+0+0'.format(*m))
        self.root.focus_set()

        self.root.configure(bg="#ddd", padx=self.PADDING, pady=self.PADDING)
        self.root.rowconfigure(0, minsize=self.ROWMIN, weight=1)
        self.root.rowconfigure(1, minsize=self.ROWMIN, weight=1)
        self.root.columnconfigure(0, minsize=self.COLMIN, weight=1)
        self.root.columnconfigure(1, minsize=self.COLMIN, weight=1)
        self.root.minsize(self.PADDING * 6 + self.COLMIN * 2,
                          self.PADDING * 6 + self.ROWMIN * 2)

        self.graph_bar = tkinter.Frame(self.root)
        self.graph_chi = tkinter.Frame(self.root, bg='#000')
        self.graph_bar.grid(row=0,
                            column=0,
                            sticky=W + E + N + S,
                            padx=self.PADDING,
                            pady=self.PADDING)
        self.graph_chi.grid(row=0,
                            column=1,
                            sticky=W + E + N + S,
                            padx=self.PADDING,
                            pady=self.PADDING)
        self.graph_bar.pack_propagate(False)
        self.graph_chi.pack_propagate(False)
        self._nullfig = Figure()
        self.canvas_bar = FigureCanvasTkAgg(self._nullfig,
                                            master=self.graph_bar)
        self.canvas_chi = FigureCanvasTkAgg(self._nullfig,
                                            master=self.graph_chi)
        self.canvas_bar.get_tk_widget().pack(fill="both", expand=True)
        self.canvas_chi.get_tk_widget().pack(fill="both", expand=True)

        self.imframe = tkinter.Frame(self.root, bg="#eee")
        self.imframe.grid(row=1,
                          column=1,
                          sticky=W + E + N + S,
                          padx=self.PADDING,
                          pady=self.PADDING)
        self.imframe.pack_propagate(False)

        self.tkimage = tkinter.Label(self.imframe, bd=0, bg='#eee')
        self.tkimage.pack(fill="both", expand=True)

        self.statframe = tkinter.Frame(self.root, bg="#eee")
        self.statframe.grid(row=1,
                            column=0,
                            sticky=W + E + N + S,
                            padx=self.PADDING,
                            pady=self.PADDING)
        self.statframe.rowconfigure(0, weight=1)
        self.statframe.rowconfigure(1, weight=1)
        self.statframe.columnconfigure(0, weight=1)
        self.statframe.columnconfigure(1, weight=1)

        self.lilfont = font.Font(family='Trebuchet MS',
                                 size=25,
                                 weight='normal')
        self.bigfont = font.Font(family='Trebuchet MS', size=75, weight='bold')

        positions = {
            "Actuations": (0, 0),
            "Dice Rolls": (0, 1),
            "Average Roll": (1, 0),
            "Chi-Squared": (1, 1)
        }
        self.sf_subs = {}
        self.sf_labels = {}
        self.sf_vars = {}
        for pos in positions:
            self.sf_subs[pos] = tkinter.Frame(self.statframe, bg='#eee')
            self.sf_subs[pos].grid(row=positions[pos][0],
                                   column=positions[pos][1],
                                   sticky=W + E + N + S,
                                   padx=30,
                                   pady=30)
            self.sf_subs[pos].rowconfigure(0, weight=1)
            self.sf_subs[pos].rowconfigure(1, weight=5)
            self.sf_subs[pos].columnconfigure(0, weight=1)
            self.sf_subs[pos].grid_propagate(False)
            self.sf_labels[pos] = tkinter.Label(self.sf_subs[pos],
                                                text=pos,
                                                font=self.lilfont,
                                                bg='#eee')
            self.sf_labels[pos].grid(row=0, column=0, sticky=W + E)
            self.sf_labels[pos].grid_propagate(False)
            self.sf_vars[pos] = tkinter.Label(self.sf_subs[pos],
                                              text="0",
                                              font=self.bigfont,
                                              bg='#eee')
            self.sf_vars[pos].grid(row=1, column=0, sticky=W + E)
            self.sf_vars[pos].grid_propagate(False)

        self.actuations = 0
        self.chi_history = []
        self.die = Die("D20", 20)

        self.vision = VisionThread()
        self.vision.start()

        self.state = self.States.SAMPLE
        self.root.after(1, self.tick)

    def tick(self):
        if self.state == self.States.SAMPLE:
            self.vision.sample()
            self.state = self.States.SAMPLE_WAIT
        if self.state == self.States.SAMPLE_WAIT:
            with self.vision.reslock:
                if self.vision.fresh:
                    self.state = self.States.SAMPLE_READY
        if self.state == self.States.SAMPLE_READY:
            dice, frame = self.vision.wait_results()
            self.show_frame(frame)
            self.update_stats(dice)
            self.state = self.States.SAMPLE

        self.root.after(10, self.tick)

    def show_frame(self, frame):
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
        size = clamp_aspect(16.0 / 9.0, self.tkimage.winfo_width(),
                            self.tkimage.winfo_height())
        frame = cv2.resize(frame, size)
        frame = Image.fromarray(frame)
        frame = ImageTk.PhotoImage(frame)
        self.tkimage.configure(image=frame)
        self.tkimage.image = frame

    def update_stats(self, dice):
        self.actuations += 1
        for roll in dice:
            self.die.add_roll(roll)

        self.sf_vars["Actuations"].configure(
            text="{:d}".format(self.actuations))
        if self.die.rolls() < 1:
            return

        self.chi_history.append(self.die.chi_squared())
        self.sf_vars["Dice Rolls"].configure(
            text="{:d}".format(self.die.rolls()))
        self.sf_vars["Average Roll"].configure(
            text="{:2.2f}".format(self.die.average()))
        self.sf_vars["Chi-Squared"].configure(
            text="{:2.2f}".format(self.chi_history[-1]))

        class FakeEvent:
            def __init__(self, width, height):
                self.width = width
                self.height = height

        self.canvas_chi.figure = graphs.chi_graph(self.chi_history)
        self.canvas_chi.resize(
            FakeEvent(self.graph_chi.winfo_width(),
                      self.graph_chi.winfo_height()))
        self.canvas_bar.figure = graphs.count_graph(self.die)
        self.canvas_bar.resize(
            FakeEvent(self.graph_bar.winfo_width(),
                      self.graph_bar.winfo_height()))

    def shutdown(self):
        self.root.destroy()
        self.vision.stop()
        self.vision.join(timeout=10)
        exit(0)

    def run(self):
        self.root.protocol("WM_DELETE_WINDOW", self.shutdown)
        self.root.mainloop()