title: pygame - Scrolling down page
body: <p>My program in a nutshell is a Contacts App, which obviously means that a person needs to be able to store a number of contacts in the app, which in turn means that contacts are going to eventually go "off" the screen, so I need to be able to scroll down the page so that a person can see all their contacts and interact with a specific contact.</p>
  
  <p>However, I'm in a bit of pickle... how do I do this? The problems I'm facing is that the app is a fixed width and height so I can't scroll down the page only to find that the background is going to be black because my rectangle was only sized to be as long as the apps window length. The other problem is I just don't know how to 'push' the screen up. I just have no idea.</p>
  
  <p>Here is the code for the program so far:</p>
  
  <pre><code>import pickle
  import operator
  import pygame
  import sys
  from pygame.locals import *
  from itertools import groupby
  
  #create Contact class
  class Contact():
      def __init__(self, firstName, lastName, address, groupType,
                   telephone, mobile, email, photoField):
          self.firstName = firstName
          self.lastName = lastName
          self.address = address
          self.groupType = groupType
          self.telephone = telephone
          self.mobile = mobile
          self.email = email
          self.photoField = photoField
  
      def showDetails(self):
          print("First Name:\t", self.firstName)
          print("Last Name:\t", self.lastName)
          print("Address:\t", self.address)
          print("Telephone:\t", self.telephone)
          print("Mobile:\t", self.mobile)
          print("Email:\t", self.email)
  
      @classmethod
      def from_input(cls):
          firstName = input("First Name: ")
          lastName = input("Last Name: ")
          address = input("Address: ")
          telephone = input("Telephone: ")
          mobile = input("Mobile: ")
          email = input("Email: ")
          return cls(firstName, lastName, address, None,
  
                     telephone, mobile, email, None)
  
  class AddressBook():
      def __init__(self):
          self.contactsList = pickle.load(open("save.p", "rb"))
  
      def addContact(self, contact = None):
          if contact is None:
              contact = Contact.from_input()
          self.contactsList.append(contact)
          pickle.dump(self.contactsList, open("save.p", "wb"))
  
      def delContact(self, contact = None):
          if contact is None:
              search = input("Search: ")
              for i in self.contactsList:
                  if (i.firstName.lower() == search.lower()) or (i.lastName.lower() == search.lower()):
                      indexed = self.contactsList.index(i)
                      del self.contactsList[indexed]
                      pickle.dump(self.contactsList, open("save.p", "wb"))
                  elif (i.firstName.lower() != search.lower()) or (i.lastName.lower() != search.lower()):
                      continue
  
      def contactInfo(self, contact = None):
          if contact is None:
              search = input("Search: ")
              print()
  
              #display contact information
              for i in self.contactsList:
                  if (i.firstName.lower() == search.lower()) or (i.lastName.lower() == search.lower()):
                      i.showDetails()
                      print()
                  elif (i.firstName.lower() != search.lower()) or (i.lastName.lower() != search.lower()):
                      continue
                  else:
                      print("No contacts\n")
  
      def contactSearch(self, contact = None):
          if contact is None:
              search = input("Search: ")
              print()
  
              for i in self.contactsList:
                  if (i.firstName.lower() == search.lower()) or (i.lastName.lower() == search.lower()):
                      print(i.firstName, i.lastName)
                      print()
                  elif (i.firstName.lower() != search.lower()) or (i.lastName.lower() != search.lower()):
                      continue
                  else:
                      print("No contacts\n")
  
  class Page():
      def __init__(self, screen = pygame.display.set_mode((320, 480)), caption = pygame.display.set_caption("Contacts")):
          self.screen = screen
          self.caption = caption
  
      def style(self):
          pygame.draw.rect(self.screen, (171,0,0), (0,0,320,63), 0)
          pygame.draw.rect(self.screen, (230,230,230), (0,63,320,417), 0)
          pygame.draw.line(self.screen, (120,0,0), (5,61), (320, 61), 2)
  
  class MainPage(Page):
      def __init__(self, screen = pygame.display.set_mode((320, 480)), caption = pygame.display.set_caption("Contacts"), title = "Contacts"):
          Page.__init__(self, screen, caption)
          self.title = title
  
      def style(self):
          Page.style(self)
          titleFont = pygame.font.SysFont("trebuchet ms", 38)
          textSurface = titleFont.render(self.title, True, (255,255,255))
          self.screen.blit(textSurface, (5, 18))
          AddButton().shape()
  
      def printContacts(self):
          addressBook = AddressBook()
          addressBook.contactsList
          addressBook.contactsList.sort(key = lambda c: (c.lastName, c.firstName) if c.lastName else (c.firstName, ""))
          contactFont = pygame.font.SysFont("trebuchet ms", 18)
          y = 80
  
          for (key, g) in groupby(addressBook.contactsList, lambda c: c.lastName[0] if c.lastName else c.firstName[0]):
              groupName = contactFont.render(key, True, (171,0,0))
              self.screen.blit(groupName, (5, y))
              pygame.draw.line(self.screen, (0,0,0), (5,(y+20)), (320, (y+20)), 1)
              y += 30
  
              for i in g:
                  name = i.firstName + " " + i.lastName
                  textName = contactFont.render(name, True, (0,0,0))
                  pygame.draw.line(self.screen, (210,210,210), (5,(y+20)), (320, (y+20)), 1)
                  self.screen.blit(textName, (5, y))
                  y += 30
  
  class AddPage(Page):
      def __init__(self, screen = pygame.display.set_mode((320, 480)), caption = pygame.display.set_caption("Contacts"), title = "Add Contact"):
          Page.__init__(self, screen, caption)
          self.title = title
  
      def style(self):
          Page.style(self)
          titleFont = pygame.font.SysFont("trebuchet ms", 38)
          textSurface = titleFont.render(self.title, True, (255,255,255))
          self.screen.blit(textSurface, (5, 18))
          AddButton().shape()
          CancelButton().shape()
  
  class Button():
      def __init__(self, screen = pygame.display.set_mode((320, 480))):
          self.screen = screen
  
      def shape(self): 
          pygame.draw.rect(self.screen, (120,0,0), (270,12,40,40), 0)
  
  class AddButton(Button):
      def __init__(self, screen = pygame.display.set_mode((320, 480))):
          Button.__init__(self, screen)
  
      def shape(self):
          Button.shape(self)
          pygame.draw.line(self.screen, (255,255,255), (289, 15), (289,48), 2)
          pygame.draw.line(self.screen, (255,255,255), (272, 31.5), (307, 31.5), 2)
  
  class CancelButton(Button):
      def __init__(self, screen = pygame.display.set_mode((320, 480))):
          Button.__init__(self, screen)
  
      def shape(self):
          pygame.draw.rect(self.screen, (120,0,0), (245,20,25,25), 0)
          pygame.draw.aaline(self.screen, (255,255,255), (252,32.5), (263,26))
          pygame.draw.aaline(self.screen, (255,255,255), (252,32.5), (263,39))
  
  pygame.init()
  page = MainPage()
  page.style()
  page.printContacts()
  
  while True:    
      for event in pygame.event.get():
          if event.type == QUIT:
              pygame.quit()
              sys.exit()
          elif event.type == KEYDOWN and event.key == K_ESCAPE:
              pygame.quit()
              sys.exit()  
          elif event.type == MOUSEBUTTONUP and event.button == 1 and isinstance(page, MainPage):
              if (pygame.mouse.get_pos() &gt;= (270,13)) and (pygame.mouse.get_pos() &gt;= (270,53)) and (pygame.mouse.get_pos() &lt;= (309,13)) and (pygame.mouse.get_pos() &lt;= (309,53)):
                  page = AddPage()
                  page.style()
          elif event.type == MOUSEBUTTONUP and event.button == 1 and isinstance(page, AddPage):
              if (pygame.mouse.get_pos() &gt;= (270,13)) and (pygame.mouse.get_pos() &gt;= (270,53)) and (pygame.mouse.get_pos() &lt;= (309,13)) and (pygame.mouse.get_pos() &lt;= (309,53)):
                  page = MainPage()
                  page.style()
                  page.printContacts()
              elif (pygame.mouse.get_pos() &gt;= (245,20)) and (pygame.mouse.get_pos() &gt;= (245,45)) and (pygame.mouse.get_pos() &lt;= (370,20)) and (pygame.mouse.get_pos() &lt;= (370,45)):
                  page = MainPage()
                  page.style()
                  page.printContacts()
  
      pygame.display.update()
  
      addressBook = AddressBook()
      addressBook.contactsList
      addressBook.contactsList.sort(key = lambda c: (c.lastName, c.firstName) if c.lastName else (c.firstName, ""))
  
      print("-------------------\nContacts\n")
      for i in addressBook.contactsList:
          print(i.firstName, i.lastName)
      print()
  
      print("Menu:\n\n1. Add Contact\n2. Show Contact Details\n3. Edit Contact\n4. Delete Contact\n5. Search Contact\n-------------------\n")
  
      choice = input()
      print()
  
      if choice == "1":
          #add contacts
  
          contact = AddressBook().addContact()
  
      elif choice == "2":
          contact = AddressBook().contactInfo()
  
      elif choice == "4":
          contact = AddressBook().delContact()
  
      elif choice == "5":
          contact = AddressBook().contactSearch()
  
      else:
          continue
  </code></pre>
  
  <p>I apologise for the mixture of pygame code and raw python code, as I still haven't fully transitioned the shell code into code that's usable by pygame. So contact entries etc are still done via the Shell/console. I first want to complete the main screen before I move on to actually being able to pass inputs via pygame. </p>