Ejemplo n.º 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):
        """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
        # ...
        # create input/output/button wedgets
        self._input_widget = ItemGridView(self, input_size)
        self._crafting_button = tk.Button(self, text=" => Craft => ")
        self._output_widget = ItemGridView(self, (1, 1))
        self._input_widget.pack(side=tk.LEFT)
        self._crafting_button.pack(side=tk.LEFT)
        self._output_widget.pack(side=tk.TOP)

    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: Render 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_widget.draw_cell((0, 0), stack, key == selected)

            else:
                # Task 2.2 Crafting: Draw input cells
                # ...

                self._input_widget.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_widget.bind(
            event,
            lambda e: callback(self._input_widget.xy_to_grid((e.x, e.y)), e))
        self._output_widget.bind(event, lambda e: callback("output", e))
        self._crafting_button.bind(event, lambda e: callback("craft", e))
Ejemplo n.º 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)
        self._master = master
        self._crafting_type = 'basic'

        # Task 2.2 Crafting: Create widgets here
        # ...
        print(input_size)
        if input_size == (2, 1):
            self._crafting_type = 'furnace'

            # Frame for the smelting item, fuel and fire image
            self._furnace_frame = tk.Frame(self)

            # Create one grid for the item to be smelted
            self._smelt_grid = Grid(rows=1, columns=1)
            self._smelt_grid_view = ItemGridView(self._furnace_frame, (1, 1))
            self._smelt_grid_view.pack(side=tk.TOP, expand=True)

            # Flame
            self._flame_img = ImageTk.PhotoImage(Image.open('flame.png'))
            self._flame_label = tk.Label(self._furnace_frame,
                                         image=self._flame_img)
            self._flame_label.pack(side=tk.TOP)

            # Create on grid below the fire for the fuel item
            self._fuel_grid = Grid(rows=1, columns=1)
            self._fuel_grid_view = ItemGridView(self._furnace_frame, (1, 1))
            self._fuel_grid_view.pack(side=tk.TOP, expand=True)

            # Render and pack
            self._smelt_grid_view.render(self._smelt_grid.items(), None)
            self._fuel_grid_view.render(self._fuel_grid.items(), None)
            self._furnace_frame.pack(side=tk.LEFT, expand=True)
        else:  # Basic crafting grid for 2x2 or crafting table
            self._input_grid = Grid(rows=input_size[0], columns=input_size[1])
            self._input_grid_view = ItemGridView(self,
                                                 self._input_grid.get_size())
            self._input_grid_view.pack(side=tk.LEFT, expand=True)
            self._input_grid_view.render(self._input_grid.items(), None)

        # Create output cell and craft button, the same for all cases
        self._output_cell = Grid(rows=1, columns=1)
        self._output_cell_view = ItemGridView(self,
                                              self._output_cell.get_size())
        self._output_cell_view.pack(side=tk.RIGHT, expand=True)

        self._craft_button = tk.Button(self, text='=>Craft=>')
        self._craft_button.pack(side=tk.LEFT)

        self._output_cell_view.render(self._output_cell.items(), None)

    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: Render widgets here
        # ...
        #print(f"{selected} is selected")
        #print(key_stack_pairs)
        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_cell_view.draw_cell((0, 0),
                                                 stack,
                                                 active=selected == key)
            elif self._crafting_type == 'furnace' and key == (0, 0):
                self._smelt_grid_view.draw_cell((0, 0),
                                                stack,
                                                active=selected == key)
            elif self._crafting_type == 'furnace' and key == (1, 0):
                self._fuel_grid_view.draw_cell((0, 0),
                                               stack,
                                               active=selected == key)
            elif self._crafting_type == 'basic':
                # Task 2.2 Crafting: Draw input cells
                # ...
                self._input_grid_view.draw_cell(key,
                                                stack,
                                                active=selected == key)

    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)
        #
        # ...
        if self._crafting_type == 'basic':
            self._input_grid_view.bind(
                event, lambda e: callback(
                    self._input_grid_view.xy_to_grid((e.x, e.y)), e))
        elif self._crafting_type == 'furnace':
            self._smelt_grid_view.bind(event, lambda e: callback((0, 0), e))
            self._fuel_grid_view.bind(event, lambda e: callback((1, 0), e))
        self._output_cell_view.bind(event, lambda e: callback("output", e))
        self._craft_button.bind(event, lambda e: callback('craft', 'craft'))