Exemplo n.º 1
0
    def __init__(self, width, height, owner):

        ScreenGUI.__init__(self, width, height, owner)

        border = Border(width, height)

        self.buttons = Enum("BARCODE", "DESCRIPTION", "PRICE", "DONE",
                            "CANCEL")

        # #
        # # Fixed position objects
        # #

        minx = border.inner_x() + 4 * Widths.BORDER
        maxx = width - Widths.BORDER
        miny = border.inner_y() + 4 * Widths.BORDER
        maxy = height - Widths.BORDER

        buttonh = 50
        buttonw = 100

        fullwidth = maxx - minx

        self.default_text = {
            self.buttons.BARCODE: "1. Scan an item",
            self.buttons.DESCRIPTION: "2. Type a description",
            self.buttons.PRICE: "3. Set a price",
        }

        self.objects = {
            self.buttons.BARCODE:
            LCARSCappedBar(pygame.Rect(minx, miny, fullwidth, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "1. Scan an item", Colours.ENTRY, Colours.BG, True),
            self.buttons.DESCRIPTION:
            LCARSCappedBar(
                pygame.Rect(minx, miny + (2 * buttonh), fullwidth, buttonh),
                CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                "2. Type a description", Colours.ERR, Colours.BG, True),
            self.buttons.PRICE:
            LCARSCappedBar(
                pygame.Rect(minx, miny + (4 * buttonh), fullwidth, buttonh),
                CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "3. Set a price",
                Colours.ERR, Colours.BG, True),
            self.buttons.DONE:
            LCARSCappedBar(pygame.Rect(minx, maxy - buttonh, buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "Done", Colours.FG, Colours.BG, True),
            self.buttons.CANCEL:
            LCARSCappedBar(
                pygame.Rect(maxx - buttonw, maxy - buttonh, buttonw, buttonh),
                CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Cancel",
                Colours.FG, Colours.BG, True),
        }

        # #
        # # Import standard objects
        # #
        self.objects.update(border.get_border())
Exemplo n.º 2
0
    def __init__(self, width, height, owner):

        ScreenGUI.__init__(self, width, height, owner)

        border = Border(width, height)

        self.buttons = Enum("BARCODE", "DESCRIPTION", "PRICE", "DONE", "CANCEL")

        # #
        # # Fixed position objects
        # #

        minx = border.inner_x() + 4 * Widths.BORDER
        maxx = width - Widths.BORDER
        miny = border.inner_y() + 4 * Widths.BORDER
        maxy = height - Widths.BORDER

        buttonh = 50
        buttonw = 100

        fullwidth = maxx - minx

        self.default_text = {
                        self.buttons.BARCODE : "1. Scan an item",
                        self.buttons.DESCRIPTION : "2. Type a description",
                        self.buttons.PRICE : "3. Set a price",
                        }

        self.objects = {
            self.buttons.BARCODE        : LCARSCappedBar(pygame.Rect(minx, miny, fullwidth, buttonh), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "1. Scan an item", Colours.ENTRY, Colours.BG, True),
            self.buttons.DESCRIPTION    : LCARSCappedBar(pygame.Rect(minx, miny + (2 * buttonh), fullwidth, buttonh), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "2. Type a description", Colours.ERR, Colours.BG, True),
            self.buttons.PRICE          : LCARSCappedBar(pygame.Rect(minx, miny + (4 * buttonh), fullwidth, buttonh), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "3. Set a price", Colours.ERR, Colours.BG, True),
            self.buttons.DONE           : LCARSCappedBar(pygame.Rect(minx, maxy - buttonh, buttonw, buttonh), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Done", Colours.FG, Colours.BG, True),
            self.buttons.CANCEL         : LCARSCappedBar(pygame.Rect(maxx - buttonw, maxy - buttonh, buttonw, buttonh), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Cancel", Colours.FG, Colours.BG, True),
        }

        # #
        # # Import standard objects
        # #
        self.objects.update(border.get_border())
Exemplo n.º 3
0
    def __init__(self, width, height, owner):

        ScreenGUI.__init__(self, width, height, owner)

        border = Border(width, height)

        ##
        ## Fixed position objects
        ##

        buttonw = 100
        largebuttonw = buttonw * 2
        amountentryw = (buttonw * 4) + (Widths.BORDER * 4)

        ## Column and row x, y locations
        cx = [0, 0, 0, 0]  #pylint: disable=C0103
        cx[0] = 200
        cx[1] = cx[0] + buttonw + Widths.BORDER
        cx[2] = cx[1] + buttonw + Widths.BORDER
        cx[3] = cx[2] + buttonw + Widths.BORDER + Widths.BORDER
        buttonh = 50
        amountentryh = buttonh * 1.5

        ry = [0, 0, 0, 0]  #pylint: disable=C0103
        ry[0] = 125
        ry[1] = ry[0] + amountentryh + Widths.BORDER
        ry[2] = ry[1] + buttonh + Widths.BORDER
        ry[3] = ry[2] + buttonh + Widths.BORDER
        r5y = ry[3] + buttonh + Widths.BORDER
        r6y = r5y + buttonh + Widths.BORDER

        cancelbuttonx = cx[
            3] + buttonw - largebuttonw  #Right align the "cancel" button

        self.keys = Enum("KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5",
                         "KEY6", "KEY7", "KEY8", "KEY9", "FIVEPOUNDS",
                         "TENPOUNDS", "TWENTYPOUNDS", "DONE", "CANCEL",
                         "AMOUNT")

        self.objects = {
            self.keys.AMOUNT:
            LCARSCappedBar(
                pygame.Rect(cx[0], ry[0], amountentryw, amountentryh),
                CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "\xA30.00",
                Colours.FG, Colours.BG, True),
            self.keys.KEY0:
            LCARSCappedBar(pygame.Rect(cx[0], r5y, buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "0",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY1:
            LCARSCappedBar(pygame.Rect(cx[0], ry[3], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "1",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY2:
            LCARSCappedBar(pygame.Rect(cx[1], ry[3], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "2",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY3:
            LCARSCappedBar(pygame.Rect(cx[2], ry[3], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "3",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY4:
            LCARSCappedBar(pygame.Rect(cx[0], ry[2], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "4",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY5:
            LCARSCappedBar(pygame.Rect(cx[1], ry[2], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "5",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY6:
            LCARSCappedBar(pygame.Rect(cx[2], ry[2], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "6",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY7:
            LCARSCappedBar(pygame.Rect(cx[0], ry[1], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "7",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY8:
            LCARSCappedBar(pygame.Rect(cx[1], ry[1], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "8",
                           Colours.FG, Colours.BG, True),
            self.keys.KEY9:
            LCARSCappedBar(pygame.Rect(cx[2], ry[1], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "9",
                           Colours.FG, Colours.BG, True),
            self.keys.FIVEPOUNDS:
            LCARSCappedBar(pygame.Rect(cx[3], ry[1], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           u"\xA35", Colours.FG, Colours.BG, True),
            self.keys.TENPOUNDS:
            LCARSCappedBar(pygame.Rect(cx[3], ry[2], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           u"\xA310", Colours.FG, Colours.BG, True),
            self.keys.TWENTYPOUNDS:
            LCARSCappedBar(pygame.Rect(cx[3], ry[3], buttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           u"\xA320", Colours.FG, Colours.BG, True),
            self.keys.DONE:
            LCARSCappedBar(pygame.Rect(cx[0], r6y, largebuttonw, buttonh),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "Done", Colours.FG, Colours.BG, True),
            self.keys.CANCEL:
            LCARSCappedBar(
                pygame.Rect(cancelbuttonx, r6y, largebuttonw, buttonh),
                CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Cancel",
                Colours.FG, Colours.BG, True),
        }

        ##
        ## Import standard objects

        self.objects.update(border.get_border())
Exemplo n.º 4
0
class IntroScreenGUI(ScreenGUI):

    """ Describes the graphical elements of the intro screen and
    provides methods for setting introduction text """
    
    def __init__(self, width, height, owner):

        ScreenGUI.__init__(self, width, height, owner)

        self.border = Border(width, height)

        ##
        ## Fixed position objects
        ##
        self.path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory
        self.objects = {
                'titleimage' : LCARSImage(pygame.Rect(width/2, height*3/5, 0, 0), self.path + LOGO_PATH, True),
                }

        ##
        ## Import standard objects

        self.objects.update(self.border.get_border())

        ##
        ## Position-dependant objects
        ##

        self.set_intro_text("Searching for remote database...", Colours.FG)
        self.set_intro_text_2("Don't have a card? Seeing error messages?", Colours.FG)
        self.set_intro_text_3("Pop money in the pot instead!", Colours.FG)

    def set_intro_text(self, text, color):
        """ The intro text is positioned centrally between the sweep and image """
        text_y_position = (self.border.inner_y() + self.objects['titleimage'].t()) / 2
        self.objects['introtext'] = LCARSText((self.width/2, text_y_position),
                text,
                36,
                TextAlign.XALIGN_CENTRE, color, Colours.BG, True)

    def set_intro_text_2(self, text, color):
        """ The intro text is positioned between the image and the base """
        text_y_position = (self.objects['titleimage'].b() + self.border.bottom()) / 2
	text_y_position = text_y_position - 30
        self.objects['introtext2'] = LCARSText((self.width/2, text_y_position),
                text,
                36,
                TextAlign.XALIGN_CENTRE, color, Colours.BG, True)

    def set_intro_text_3(self, text, color):
        """ The intro text is positioned between the image and the base """
        text_y_position = self.objects['introtext2'].t() + 80
        self.objects['introtext3'] = LCARSText((self.width/2, text_y_position),
                text,
                36,
                TextAlign.XALIGN_CENTRE, color, Colours.BG, True)

    def draw(self, window):
        
        """ Draw the screen objects on the supplied window """
        
        window.fill(Colours.BG)

        for draw_obj in self.objects.values():
            draw_obj.draw(window)

        #Ensure text is drawn on top
        self.objects['introtext'].draw(window)
        self.objects['introtext2'].draw(window)
        self.objects['introtext3'].draw(window)
        
        if self.banner is not None:
            self.banner.draw(window)
            
        pygame.display.flip()
Exemplo n.º 5
0
class MainScreenGUI(ScreenGUI):

    """ Describes the graphical elements of the main screen and
    provides methods for adding and remove products """
    
    def __init__(self, width, height, owner):
        
        ScreenGUI.__init__(self, width, height, owner)
        self.border = Border(width, height)

        # Object constant definitions
        # Reverse draw order - 0 drawn last
        self.ids = Enum("DONE", "CANCEL", "PAY", "TOPBAR", "AMOUNT", "UP", "DOWN", "PRODUCT", "REMOVE")
        
        self.limits = Const()
        self.limits.screen_products = 5
        self.limits.objects_per_product_row = 3

        self.logger = logging.getLogger("MainScreen.GUI")
        
        self.product_displays = ProductDisplayCollection(self.limits.screen_products)
        
        # #
        # # Fixed position objects
        # #
        self.layout = MainScreenLayout(width, height, self.border)

        self.objects = {
            self.ids.DONE: LCARSCappedBar(
                self.layout.get_done_rect(), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Done", Colours.FG, Colours.BG, False),
            self.ids.PAY:LCARSCappedBar(
                self.layout.get_pay_rect(), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Pay debt", Colours.FG, Colours.BG, False),
            self.ids.CANCEL:LCARSCappedBar(
                self.layout.get_cancel_rect(), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Cancel", Colours.FG, Colours.BG, True),
            self.ids.TOPBAR:LCARSCappedBar(
                self.layout.get_top_bar_rect(), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "User: <No user scanned>", Colours.FG, Colours.BG, True),
            self.ids.UP: LCARSCappedBar(
                self.layout.get_up_scroll_rect(), CapLocation.CAP_TOP, "UP", Colours.FG, Colours.BG, False),
            self.ids.DOWN: LCARSCappedBar(
                self.layout.get_down_scroll_rect(), CapLocation.CAP_BOTTOM, "DN", Colours.FG, Colours.BG, False),
            self.ids.AMOUNT:LCARSCappedBar(
                self.layout.get_amount_rect(), CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT, "Total Spend: \xA30.00", Colours.FG, Colours.BG, True)
        }

        # #
        # # Import standard objects
        # #
        self.objects.update(self.border.get_border())
                  
    def add_to_product_display(self, product):
        """ Add a new product to the list """
        self.product_displays.add(product)

    def update_total(self):
        """ Update the total spend value """
        self.objects[self.ids.AMOUNT].setText("Total Spend: \xA3%.2f" % (self.owner.total_price() / 100))

    def _remove_button_width(self):
        """ The width of the remove button depends on whether the up/dn buttons are displayed """
        removew = self.width - self.layout.product_entries.remove_x - Widths.BORDER

        if self._test_display_down_button() or self._test_display_up_button():
            removew -= (self.layout.scroll.width + Widths.BORDER)

        return removew

    def get_object_id(self, pos):
        """ Returns the ID of the object at the given position """
        object_id = ScreenGUI.get_object_id(self, pos)

        if object_id == -1:
            # Try searching remove buttons
            if self.product_displays.collide_on_remove(pos) is not None:
                object_id = self.ids.REMOVE
            
        return object_id

    def set_unknown_user(self):
        """ Indicate that an unknown card was scanned """
        self.objects[self.ids.TOPBAR].setText("User: <Unknown card>")

    def set_user(self, name, balance, credit):
        """ Set the current username """
        if balance >= 0:
            text = u"%s (Balance: \xA3%.2f" % (name, balance / 100)
        else:
            text = u"%s (Balance: -\xA3%.2f" % (name, -balance / 100)

        if credit > 0:
            text += u", Pending Credit: \xA3%.2f" % (credit / 100)

        text += ")"

        self.objects[self.ids.TOPBAR].setText(text)

    def _test_display_up_button(self):
        """ Returns TRUE if the up button should be displayed """
        return (self.product_displays.top_index > 0)

    def _test_display_down_button(self):
        """ Returns TRUE if the down button should be displayed """
        return (self.product_displays.top_index + self.limits.screen_products) < len(self.product_displays)

    def clear_products(self):
        """ Reset the products list to nothing """
        self.product_displays.clear()

    def draw(self, window):
        
        """ Redraw the main screen """
        window.fill(Colours.BG)

        self._set_show_hide_products()
        self._draw_products(window)
        self._draw_static_objects(window)

        pygame.display.flip()

    def _set_show_hide_products(self):

        """ Scan down the product list and set the visible
        state of the product objects """
        
        visible_count = 0

        for (counter, product) in enumerate(self.product_displays):

            if (counter < self.product_displays.top_index):
                # Hide all the products above the list product top
                product.set_visible(False)
            elif visible_count < self.limits.screen_products:
                # Show screen products based on their quantity
                product.visible = True
                visible_count += 1
            else:
                # Hide products below list bottom
                product.set_visible(False)

    def _draw_products(self, window):

        """ Draw all visible product objects on the window """
        
        # Iterate over all products in list
        index = 0
        for product in self.product_displays:
            if product.visible:
                product.draw(self.layout, index, self._remove_button_width(), window)
                index += 1

    def _draw_static_objects(self, window):

        """ Draw all the static objects on the window """
        
        self.update_total()

        ## Draw border
        for draw_object in self.border.get_border().values():
            draw_object.draw(window)

        # Draw the fixed objects
        static_objs = [
                self.objects[self.ids.TOPBAR],
                self.objects[self.ids.PAY],
                self.objects[self.ids.CANCEL],
                self.objects[self.ids.DONE],
                self.objects[self.ids.AMOUNT],
                self.objects[self.ids.UP],
                self.objects[self.ids.DOWN]
        ]

        # Decide which objects should be shown
        if self.owner.user is not None:
            self.objects[self.ids.PAY].visible = self.owner.user.credit_allowed()
            self.objects[self.ids.DONE].visible = self.owner.user.has_added_credit() or (len(self.product_displays) > 0)
            
        self.objects[self.ids.UP].visible = self._test_display_up_button()
        self.objects[self.ids.DOWN].visible = self._test_display_down_button()

        for static_obj in static_objs:
            static_obj.draw(window)

        if self.banner is not None:
            self.banner.draw(window)

    def active(self):
        """ Abstraction for the active state of the screen """
        return self.owner.active
Exemplo n.º 6
0
class IntroScreenGUI(ScreenGUI):
    """ Describes the graphical elements of the intro screen and
    provides methods for setting introduction text """
    def __init__(self, width, height, owner):

        ScreenGUI.__init__(self, width, height, owner)

        self.border = Border(width, height)

        ##
        ## Fixed position objects
        ##
        self.path = os.path.dirname(
            os.path.abspath(inspect.getfile(
                inspect.currentframe())))  # script directory
        self.objects = {
            'titleimage':
            LCARSImage(pygame.Rect(width / 2, height * 3 / 5, 0, 0),
                       self.path + LOGO_PATH, True),
        }

        ##
        ## Import standard objects

        self.objects.update(self.border.get_border())

        ##
        ## Position-dependant objects
        ##

        self.set_intro_text("Searching for remote database...", Colours.FG)
        self.set_intro_text_2("Don't have a card? Seeing error messages?",
                              Colours.FG)
        self.set_intro_text_3("Pop money in the pot instead!", Colours.FG)

    def set_intro_text(self, text, color):
        """ The intro text is positioned centrally between the sweep and image """
        text_y_position = (self.border.inner_y() +
                           self.objects['titleimage'].t()) / 2
        self.objects['introtext'] = LCARSText(
            (self.width / 2, text_y_position), text, 36,
            TextAlign.XALIGN_CENTRE, color, Colours.BG, True)

    def set_intro_text_2(self, text, color):
        """ The intro text is positioned between the image and the base """
        text_y_position = (self.objects['titleimage'].b() +
                           self.border.bottom()) / 2
        text_y_position = text_y_position - 30
        self.objects['introtext2'] = LCARSText(
            (self.width / 2, text_y_position), text, 36,
            TextAlign.XALIGN_CENTRE, color, Colours.BG, True)

    def set_intro_text_3(self, text, color):
        """ The intro text is positioned between the image and the base """
        text_y_position = self.objects['introtext2'].t() + 80
        self.objects['introtext3'] = LCARSText(
            (self.width / 2, text_y_position), text, 36,
            TextAlign.XALIGN_CENTRE, color, Colours.BG, True)

    def draw(self, window):
        """ Draw the screen objects on the supplied window """

        window.fill(Colours.BG)

        for draw_obj in self.objects.values():
            draw_obj.draw(window)

        #Ensure text is drawn on top
        self.objects['introtext'].draw(window)
        self.objects['introtext2'].draw(window)
        self.objects['introtext3'].draw(window)

        if self.banner is not None:
            self.banner.draw(window)

        pygame.display.flip()
Exemplo n.º 7
0
class MainScreenGUI(ScreenGUI):
    """ Describes the graphical elements of the main screen and
    provides methods for adding and remove products """
    def __init__(self, width, height, owner):

        ScreenGUI.__init__(self, width, height, owner)
        self.border = Border(width, height)

        # Object constant definitions
        # Reverse draw order - 0 drawn last
        self.ids = Enum("DONE", "CANCEL", "PAY", "TOPBAR", "AMOUNT", "UP",
                        "DOWN", "PRODUCT", "REMOVE")

        self.limits = Const()
        self.limits.screen_products = 5
        self.limits.objects_per_product_row = 3

        self.logger = logging.getLogger("MainScreen.GUI")

        self.product_displays = ProductDisplayCollection(
            self.limits.screen_products)

        # #
        # # Fixed position objects
        # #
        self.layout = MainScreenLayout(width, height, self.border)

        self.objects = {
            self.ids.DONE:
            LCARSCappedBar(self.layout.get_done_rect(),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "Done", Colours.FG, Colours.BG, False),
            self.ids.PAY:
            LCARSCappedBar(self.layout.get_pay_rect(),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "Pay debt", Colours.FG, Colours.BG, False),
            self.ids.CANCEL:
            LCARSCappedBar(self.layout.get_cancel_rect(),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "Cancel", Colours.FG, Colours.BG, True),
            self.ids.TOPBAR:
            LCARSCappedBar(self.layout.get_top_bar_rect(),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "User: <No user scanned>", Colours.FG, Colours.BG,
                           True),
            self.ids.UP:
            LCARSCappedBar(self.layout.get_up_scroll_rect(),
                           CapLocation.CAP_TOP, "UP", Colours.FG, Colours.BG,
                           False),
            self.ids.DOWN:
            LCARSCappedBar(self.layout.get_down_scroll_rect(),
                           CapLocation.CAP_BOTTOM, "DN", Colours.FG,
                           Colours.BG, False),
            self.ids.AMOUNT:
            LCARSCappedBar(self.layout.get_amount_rect(),
                           CapLocation.CAP_LEFT + CapLocation.CAP_RIGHT,
                           "Total Spend: \xA30.00", Colours.FG, Colours.BG,
                           True)
        }

        # #
        # # Import standard objects
        # #
        self.objects.update(self.border.get_border())

    def add_to_product_display(self, product):
        """ Add a new product to the list """
        self.product_displays.add(product)

    def update_total(self):
        """ Update the total spend value """
        self.objects[self.ids.AMOUNT].setText("Total Spend: \xA3%.2f" %
                                              (self.owner.total_price() / 100))

    def _remove_button_width(self):
        """ The width of the remove button depends on whether the up/dn buttons are displayed """
        removew = self.width - self.layout.product_entries.remove_x - Widths.BORDER

        if self._test_display_down_button() or self._test_display_up_button():
            removew -= (self.layout.scroll.width + Widths.BORDER)

        return removew

    def get_object_id(self, pos):
        """ Returns the ID of the object at the given position """
        object_id = ScreenGUI.get_object_id(self, pos)

        if object_id == -1:
            # Try searching remove buttons
            if self.product_displays.collide_on_remove(pos) is not None:
                object_id = self.ids.REMOVE

        return object_id

    def set_unknown_user(self):
        """ Indicate that an unknown card was scanned """
        self.objects[self.ids.TOPBAR].setText("User: <Unknown card>")

    def set_user(self, name, balance, credit):
        """ Set the current username """
        if balance >= 0:
            text = u"%s (Balance: \xA3%.2f" % (name, balance / 100)
        else:
            text = u"%s (Balance: -\xA3%.2f" % (name, -balance / 100)

        if credit > 0:
            text += u", Pending Credit: \xA3%.2f" % (credit / 100)

        text += ")"

        self.objects[self.ids.TOPBAR].setText(text)

    def _test_display_up_button(self):
        """ Returns TRUE if the up button should be displayed """
        return (self.product_displays.top_index > 0)

    def _test_display_down_button(self):
        """ Returns TRUE if the down button should be displayed """
        return (self.product_displays.top_index +
                self.limits.screen_products) < len(self.product_displays)

    def clear_products(self):
        """ Reset the products list to nothing """
        self.product_displays.clear()

    def draw(self, window):
        """ Redraw the main screen """
        window.fill(Colours.BG)

        self._set_show_hide_products()
        self._draw_products(window)
        self._draw_static_objects(window)

        pygame.display.flip()

    def _set_show_hide_products(self):
        """ Scan down the product list and set the visible
        state of the product objects """

        visible_count = 0

        for (counter, product) in enumerate(self.product_displays):

            if (counter < self.product_displays.top_index):
                # Hide all the products above the list product top
                product.set_visible(False)
            elif visible_count < self.limits.screen_products:
                # Show screen products based on their quantity
                product.visible = True
                visible_count += 1
            else:
                # Hide products below list bottom
                product.set_visible(False)

    def _draw_products(self, window):
        """ Draw all visible product objects on the window """

        # Iterate over all products in list
        index = 0
        for product in self.product_displays:
            if product.visible:
                product.draw(self.layout, index, self._remove_button_width(),
                             window)
                index += 1

    def _draw_static_objects(self, window):
        """ Draw all the static objects on the window """

        self.update_total()

        ## Draw border
        for draw_object in self.border.get_border().values():
            draw_object.draw(window)

        # Draw the fixed objects
        static_objs = [
            self.objects[self.ids.TOPBAR], self.objects[self.ids.PAY],
            self.objects[self.ids.CANCEL], self.objects[self.ids.DONE],
            self.objects[self.ids.AMOUNT], self.objects[self.ids.UP],
            self.objects[self.ids.DOWN]
        ]

        # Decide which objects should be shown
        if self.owner.user is not None:
            self.objects[
                self.ids.PAY].visible = self.owner.user.credit_allowed()
            self.objects[
                self.ids.DONE].visible = self.owner.user.has_added_credit(
                ) or (len(self.product_displays) > 0)

        self.objects[self.ids.UP].visible = self._test_display_up_button()
        self.objects[self.ids.DOWN].visible = self._test_display_down_button()

        for static_obj in static_objs:
            static_obj.draw(window)

        if self.banner is not None:
            self.banner.draw(window)

    def active(self):
        """ Abstraction for the active state of the screen """
        return self.owner.active