Exemple #1
0
class GridCrafterView(tk.Frame):
    """A tkinter widget used to display crafting with a grid as input and a single cell as output"""
    def __init__(self, master, input_size, mode="normal"):
        """Constructor

        Parameters:
            master (tk.Frame | tk.Toplevel | tk.Tk): Tkinter parent widget
            input_size (tuple<int, int>):
                    The (row, column) size of the grid crafter's input grid
        """
        super().__init__(master)
        # check mode
        if mode not in ["normal", "smelting"]:
            raise NotImplementedError("Not supported mode")
        # Task 2.2 Crafting: Create widgets here
        self._input = SelectableGrid(rows=input_size[0], columns=input_size[1])
        self._input_view = ItemGridView(self, self._input.get_size())
        self._output = SelectableGrid(rows=1, columns=1)
        if mode == "smelting":
            self._button = tk.Button(self, text="=>Smelt=>", height=1)
            im = Image.open('fire.jpg')
            self.img = ImageTk.PhotoImage(im)
            # img = tk.PhotoImage(file="fire.gif")
            self._label = tk.Label(self, image=self.img)
            self._label.pack(side=tk.LEFT)
        else:
            self._button = tk.Button(self, text="=>Craft=>", height=1)
        self._input_view.pack(side=tk.LEFT)
        self._button.pack(side=tk.LEFT)
        self._output_view = ItemGridView(self, (1, 1))
        self._output_view.pack(side=tk.LEFT)
        self._input_view.render(self._input.items(),
                                self._input.get_selected())
        self._output_view.render(self._output.items(),
                                 self._output.get_selected())

    def render(self, key_stack_pairs, selected):
        """Renders the stacks at appropriate cells, as determined by 'key_stack_pairs'

        Parameters:
            key_stack_pairs (tuple<*, Stack>):
                    (key, stack) pairs, where each stack should be drawn at the cell
                    corresponding to key
            selected (*): The key that is currently selected, or None if no key is selected
        """
        # Task 2.2 Crafting: Create widgets here
        print(f"{selected} is selected")
        for key, stack in key_stack_pairs:
            print(f"Redrawing {stack} at {key}")
            if key == "output":
                # Task 2.2 Crafting: Draw output cell
                self._output_view.draw_cell((0, 0), stack,
                                            selected == "output")
            else:
                # Task 2.2 Crafting: Draw input cells
                self._input_view.draw_cell(key, stack,
                                           True if selected == key else False)

    def bind_for_id(self, event, callback):
        """Binds callback to tkinter mouse event

        Callback accept parameters: callback(key, event), where
          - key (*) is the key of the cell clicked, etc.
          - mouse_event (tk.MouseEvent) is the original mouse event from tkinter
        """
        if event not in TK_MOUSE_EVENTS:
            return
        self._input_view.bind_for_id(event, callback)
        self._output_view.bind(event, lambda e: callback("output", e))
        self._button.bind(event, lambda e: callback("craft", e))
Exemple #2
0
class GridCrafterView(tk.Frame):
    """A tkinter widget used to display crafting with a grid as input and a single cell as output"""
    def __init__(self, master, input_size):
        """Constructor

        Parameters:
            master (tk.Frame | tk.Toplevel | tk.Tk): Tkinter parent widget
            input_size (tuple<int, int>):
                    The (row, column) size of the grid crafter's input grid
        """
        super().__init__(master)

        # Task 2.2 Crafting: Create widgets here
        # ...
        self._input_grid = ItemGridView(self, input_size)
        self._input_grid.pack(side=tk.LEFT)
        self._crafter_button = tk.Button(self, text="=> Craft =>")
        self._crafter_button.pack(side=tk.LEFT)
        self._output_grid = ItemGridView(self, (1, 1))
        self._output_grid.pack(side=tk.LEFT)

    def render(self, key_stack_pairs, selected):
        """Renders the stacks at appropriate cells, as determined by 'key_stack_pairs'

        Parameters:
            key_stack_pairs (tuple<*, Stack>):
                    (key, stack) pairs, where each stack should be drawn at the cell
                    corresponding to key
            selected (*): The key that is currently selected, or None if no key is selected
        """
        # Task 2.2 Crafting: Create widgets here
        # ...
        #print(f"{selected} is selected")

        for key, stack in key_stack_pairs:
            #print(f"Redrawing {stack} at {key}")
            if key == "output":
                # Task 2.2 Crafting: Draw output cell
                # ...
                self._output_grid.draw_cell((0, 0), stack,
                                            selected == "output")
            else:
                # Task 2.2 Crafting: Draw input cells
                # ...
                self._input_grid.draw_cell(key, stack, key == selected)

    def bind_for_id(self, event, callback):
        """Binds callback to tkinter mouse event

        Callback accept parameters: callback(key, event), where
          - key (*) is the key of the cell clicked, etc.
          - mouse_event (tk.MouseEvent) is the original mouse event from tkinter
        """
        if event not in TK_MOUSE_EVENTS:
            return

        # Task 2.2 Crafting: Bind to tkinter widgets here
        # When a cell is clicked, we need to call the callback. Tkinter's bind does
        # this for us, but not exactly how we want. Tkinter bound callbacks have a single
        # parameter, the mouse event containing useful information about the click (i.e.
        # the x & y coordinates)
        #
        # However, x & y coordinates aren't that useful. The class controlling this widget
        # (i.e. CraftingWindow) only needs to know which cell was clicked. It's not
        # concerned with where it was clicked, just that it was. This is so it can easily
        # interact with the crafter model (i.e. GridCrafter) and move stacks around or
        # select/deselect them.
        #
        # To integrate with CraftingWindow, you will need to transform the callback
        # provided to tk.bind, exactly as is done in ItemGridView.bind_for_id, except
        # the first argument may not necessarily be a (row, column) position, but
        # simply an arbitrary key (for basic 2x2 crafting, the 5 keys are:
        #    "output", (0, 0), (0, 1), (1, 0), (1, 1)
        #
        # ...
        self._input_grid.bind_for_id(event, callback)
        self._output_grid.bind(event, lambda e: callback("output", e))

        self._crafter_button.bind(event, lambda e: callback("craft", e))