Exemple #1
0
class FaderWidget(QWidget):
    def __init__(self, old_widget, new_widget):
        QWidget.__init__(self, new_widget)

        self.old_pixmap = QPixmap(new_widget.size())
        old_widget.render(self.old_pixmap)
        self.pixmap_opacity = 1.0

        self.timeline = QTimeLine()
        self.timeline.valueChanged.connect(self.animate)
        self.timeline.finished.connect(self.close)
        self.timeline.setDuration(555)
        self.timeline.start()

        self.resize(new_widget.size())
        self.show()

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        painter.setOpacity(self.pixmap_opacity)
        painter.drawPixmap(0, 0, self.old_pixmap)
        painter.end()

    def animate(self, value):
        self.pixmap_opacity = 1.0 - value
        self.repaint()
Exemple #2
0
class FaderWidget(QWidget):

    def __init__(self, old_widget, new_widget):
        QWidget.__init__(self, new_widget)

        self.old_pixmap = QPixmap(new_widget.size())
        old_widget.render(self.old_pixmap)
        self.pixmap_opacity = 1.0

        self.timeline = QTimeLine()
        self.timeline.valueChanged.connect(self.animate)
        self.timeline.finished.connect(self.close)
        self.timeline.setDuration(500)
        self.timeline.start()

        self.resize(new_widget.size())
        self.show()

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        painter.setOpacity(self.pixmap_opacity)
        painter.drawPixmap(0, 0, self.old_pixmap)
        painter.end()

    def animate(self, value):
        self.pixmap_opacity = 1.0 - value
        self.repaint()
Exemple #3
0
class TimedProgressBar(QProgressBar):
    """A QProgressBar showing a certain time elapse."""
    hideOnTimeout = True

    def __init__(self, parent=None):
        super(TimedProgressBar, self).__init__(parent, minimum=0, maximum=100)
        self._timeline = QTimeLine(updateInterval=100,
                                   frameChanged=self.setValue)
        self._timeline.setFrameRange(0, 100)
        self._hideTimer = QTimer(timeout=self._done,
                                 singleShot=True,
                                 interval=3000)

    def start(self, total, elapsed=0.0):
        """Starts showing progress.
        
        total is the number of seconds (maybe float) the timeline will last,
        elapsed (defaulting to 0) is the value to start with.
        
        """
        self._hideTimer.stop()
        self._timeline.stop()
        self._timeline.setDuration(total * 1000)
        self._timeline.setCurrentTime(elapsed * 1000)
        self.setValue(self._timeline.currentFrame())
        self._timeline.resume()
        if self.hideOnTimeout:
            self.show()

    def stop(self, showFinished=True):
        """Ends the progress display.
        
        If showFinished is True (the default), 100% is shown for a few
        seconds and then the progress is reset.
        The progressbar is hidden if the hideOnTimeout attribute is True.
        
        """
        self._hideTimer.stop()
        self._timeline.stop()
        if showFinished:
            self.setValue(100)
            self._hideTimer.start()
        else:
            self._done()

    def _done(self):
        if self.hideOnTimeout:
            self.hide()
        self.reset()
class TimedProgressBar(QProgressBar):
    """A QProgressBar showing a certain time elapse."""
    hideOnTimeout = True
    def __init__(self, parent=None):
        super(TimedProgressBar, self).__init__(parent, minimum=0, maximum=100)
        self._timeline = QTimeLine(updateInterval=100, frameChanged=self.setValue)
        self._timeline.setFrameRange(0, 100)
        self._hideTimer = QTimer(timeout=self._done, singleShot=True, interval=3000)
    
    def start(self, total, elapsed=0.0):
        """Starts showing progress.
        
        total is the number of seconds (maybe float) the timeline will last,
        elapsed (defaulting to 0) is the value to start with.
        
        """
        self._hideTimer.stop()
        self._timeline.stop()
        self._timeline.setDuration(total * 1000)
        self._timeline.setCurrentTime(elapsed * 1000)
        self.setValue(self._timeline.currentFrame())
        self._timeline.resume()
        if self.hideOnTimeout:
            self.show()
        
    def stop(self, showFinished=True):
        """Ends the progress display.
        
        If showFinished is True (the default), 100% is shown for a few
        seconds and then the progress is reset.
        The progressbar is hidden if the hideOnTimeout attribute is True.
        
        """
        self._hideTimer.stop()
        self._timeline.stop()
        if showFinished:
            self.setValue(100)
            self._hideTimer.start()
        else:
            self._done()

    def _done(self):
        if self.hideOnTimeout:
            self.hide()
        self.reset()
Exemple #5
0
class StackFader(QWidget):
    """
    A widget that creates smooth transitions in a QStackedWidget.
    """
    def __init__(self, stackedWidget):
        QWidget.__init__(self, stackedWidget)
        self.curIndex = None
        self.timeline = QTimeLine()
        self.timeline.setDuration(333)
        self.timeline.finished.connect(self.hide)
        self.timeline.valueChanged.connect(self.animate)
        stackedWidget.currentChanged.connect(self.start)
        self.hide()
    
    def start(self, index):
        if self.curIndex is not None:
            stack = self.parent()
            old, new = stack.widget(self.curIndex), stack.widget(index)
            if old and new:
                self.old_pixmap = QPixmap(new.size())
                old.render(self.old_pixmap)
                self.pixmap_opacity = 1.0
                self.resize(new.size())
                self.timeline.start()
                self.raise_()
                self.show()
        self.curIndex = index
        
    def paintEvent(self, ev):
        painter = QPainter()
        painter.begin(self)
        painter.setOpacity(self.pixmap_opacity)
        painter.drawPixmap(0, 0, self.old_pixmap)
        painter.end()
        
    def animate(self, value):
        self.pixmap_opacity = 1.0 - value
        self.repaint()
Exemple #6
0
class QPageWidget(QScrollArea):
    """ The QPageWidget provides a stack widget with animated page transitions. """
    def __init__(self, parent=None, direction="ltr", rtf=False):
        """ Creates a new QPageWidget on given parent object. 

        parent: QWidget parent
        direction: "ltr" -> Left To Right
                   "ttb" -> Top To Bottom
        rtf: Return to first, if its True it flips to the first page 
             when next page requested at the last page
        """
        # First initialize, QPageWidget is based on QScrollArea
        QScrollArea.__init__(self, parent)

        # Properties for QScrollArea
        self.setFrameShape(QFrame.NoFrame)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setWidgetResizable(True)

        # Main widget, which stores all Pages in it
        self.widget = QWidget(self)

        # Layout based on QBoxLayout which supports Vertical or Horizontal layout
        if direction == "ltr":
            self.layout = QBoxLayout(QBoxLayout.LeftToRight, self.widget)
            self.__scrollBar = self.horizontalScrollBar()
            self.__base_value = self.width
        else:
            self.layout = QBoxLayout(QBoxLayout.TopToBottom, self.widget)
            self.__scrollBar = self.verticalScrollBar()
            self.__base_value = self.height
        self.layout.setSpacing(0)
        self.layout.setMargin(0)

        # Return to first
        self.__return_to_first = rtf

        # TMP_PAGE, its using as last page in stack
        # A workaround for a QScrollArea bug
        self.__tmp_page = Page(QWidget(self.widget))
        self.__pages = [self.__tmp_page]
        self.__current = 0
        self.__last = 0

        # Set main widget
        self.setWidget(self.widget)

        # Animation TimeLine
        self.__timeline = QTimeLine()
        self.__timeline.setUpdateInterval(2)

        # Updates scrollbar position when frame changed
        self.__timeline.frameChanged.connect(
            lambda x: self.__scrollBar.setValue(x))

        # End of the animation
        self.__timeline.finished.connect(self._animateFinished)

        # Initialize animation
        self.setAnimation()
        self.setDuration()

    def _animateFinished(self):
        """ Its called by TimeLine when animation finished.

        It first runs the outMethod of last Page and then the inMethod of current Page
        Finally tt gives the focus to the current page and fixes the scrollBar
        """

        # Disable other widgets
        for page in self.__pages:
            if not page == self.__pages[self.__current]:
                page.widget.setEnabled(False)

        # Run last page's outMethod if exists
        if self.__pages[self.__last].outMethod:
            self.__pages[self.__last].outMethod()

        # Run new page's inMethod if exists
        if self.__pages[self.__current].inMethod:
            self.__pages[self.__current].inMethod()

        # Give focus to the current Page
        self.__pages[self.__current].widget.setFocus()

        # Update scrollbar position for current page
        self.__scrollBar.setValue(self.__current * self.__base_value())

        # Emit currentChanged SIGNAL
        self.emit(SIGNAL("currentChanged()"))

    def event(self, event):
        """ Overrides the main event handler to catch resize events """
        # Catch Resize event
        if event.type() == QEvent.Resize:
            # Update each page size limits to mainwidget's new size
            for page in self.__pages:
                page.widget.setMinimumSize(self.size())
                page.widget.setMaximumSize(self.size())

            # Update viewport size limits to mainwidget's new size
            # It's a workaround for QScrollArea updateGeometry bug
            self.viewport().setMinimumSize(self.size())
            self.viewport().setMaximumSize(self.size())

            # Update scrollbar position for current page
            self.__scrollBar.setValue(self.__current * self.__base_value())

        # Return the Event
        return QScrollArea.event(self, event)

    def keyPressEvent(self, event):
        """ Overrides the keyPressEvent to ignore them """
        pass

    def wheelEvent(self, event):
        """ Overrides the wheelEvent to ignore them """
        pass

    def createPage(self, widget, inMethod=None, outMethod=None):
        """ Creates and adds new Page for given widget with given in/out methods.

        widget: A QWidget which is the mainwidget for this Page
        inMethod: (optional) QPageWidget triggers this method when the Page appear
        outMethod: (optional) QPageWidget triggers this method when the Page disappear
        """
        self.addPage(Page(widget, inMethod, outMethod))

    def addPage(self, page):
        """ Adds the given Page to the stack.

        page: A Page object
        """
        # First remove the last page; its __tmp_page
        self.__pages.pop()

        # Add new page
        self.__pages.append(page)
        self.layout.addWidget(page.widget)

        # Add __tmp_page to end
        self.__pages.append(self.__tmp_page)
        self.layout.addWidget(self.__tmp_page.widget)

        # Create connections for page navigation signals from new page
        self.connect(page.widget, SIGNAL("pageNext()"), self.next)
        self.connect(page.widget, SIGNAL("pagePrevious()"), self.prev)
        self.connect(page.widget, SIGNAL("setCurrent(int)"), self.setCurrent)

    def __setCurrent(self, pageNumber):
        """ Internal method to set current page index. """
        self.__last = self.__current
        self.__current = min(max(0, pageNumber), len(self.__pages) - 2)
        if pageNumber == len(self.__pages) - 1 and self.__return_to_first:
            self.__current = 0

    def setCurrent(self, pageNumber=0):
        """ Set and flip the page with given pageNumber.

        pageNumber: index number of Page (default is 0)
        """
        self.__setCurrent(pageNumber)
        self.flipPage()

    def getCurrent(self):
        """ Returns current page index. """
        return self.__current

    def getCurrentWidget(self):
        """ Returns current page widget. """
        return self.getWidget(self.getCurrent())

    def getWidget(self, pageNumber):
        """ Returns widget for given page index 

        pageNumber: index number of Page
        """
        try:
            return self.__pages[pageNumber].widget
        except:
            return None

    def count(self):
        """ Returns number of pages. """
        return len(self.__pages) - 1

    def setAnimation(self, animation=35):
        """ Set the transition animation with the given animation.

        animation: the number represents predefined QEasingCurves
                   List of predefined QEasingCurves can be found from:
                   http://doc.qt.nokia.com/4/qeasingcurve.html#Type-enum

                   Default is QEasingCurve::InOutBack (35)
        """
        self.__animation = animation
        self.__timeline.setEasingCurve(QEasingCurve(self.__animation))

    def setDuration(self, duration=400):
        """ Set the transition duration.

        duration: duration time in ms
        """
        self.__duration = duration
        self.__timeline.setDuration(self.__duration)

    def flipPage(self, direction=0):
        """ Flip the page with given direction.

        direction: can be -1, 0 or +1
                   -1: previous page (if exists)
                    0: just flip to current page
                   +1: next page (if exists)
        """
        # Enable all widgets
        for page in self.__pages:
            page.widget.setEnabled(True)

        # Check given direction
        direction = direction if direction == 0 else max(min(1, direction), -1)

        # If direction is equal to zero no need to re-set current
        if not direction == 0:
            self.__setCurrent(self.__current + direction)

        # If last page is different from new page, flip it !
        if not self.__last == self.__current:
            self.__timeline.setFrameRange(self.__scrollBar.value(),
                                          self.__current * self.__base_value())
            self.__timeline.start()

    def next(self):
        """ Helper method to flip next page. """
        self.flipPage(1)

    def prev(self):
        """ Helper method to flip previous page. """
        self.flipPage(-1)
class ParallaxSlide(QGraphicsView):

    def __init__(self):
    
        QGraphicsView.__init__(self)
        self.ofs = 0
        self.factor = 1
        self.scene = QGraphicsScene()
        self.background = None
        self.icons = []
        self.iconTimeLine = QTimeLine()
        self.backgroundTimeLine = QTimeLine()
        
        self.setScene(self.scene)
        
        self.background = self.scene.addPixmap(QPixmap(":/background.jpg"))
        self.background.setZValue(0.0)
        self.background.setPos(0, 0)
    
        for i in range(7):
            str = QString(":/icon%1.png").arg(i+1)
            icon = self.scene.addPixmap(QPixmap(str))
            icon.setPos(320+i*64, 400)
            icon.setZValue(1.0)
            self.icons.append(icon)
    
        self.setFixedSize(320, 480)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    
        self.connect(self.iconTimeLine, SIGNAL("frameChanged(int)"), self, SLOT("moveIcons(int)"))
        self.iconTimeLine.setCurveShape(QTimeLine.EaseInOutCurve)
    
        self.connect(self.backgroundTimeLine, SIGNAL("frameChanged(int)"), self, SLOT("moveBackground(int)"))
        self.connect(self.backgroundTimeLine, SIGNAL("finished()"), self, SLOT("adjustParameters()"))
        self.backgroundTimeLine.setCurveShape(QTimeLine.EaseInOutCurve)
        
        self.controls = Ui_ControlsForm()
        
        toolWidget = QWidget(self)
        toolWidget.setWindowFlags(Qt.Tool | Qt.WindowTitleHint)
        self.controls.setupUi(toolWidget)
        toolWidget.show()
    
        self.connect(self.controls.speedSlider, SIGNAL("valueChanged(int)"),
                     self, SLOT("adjustParameters()"))
        self.connect(self.controls.normalButton, SIGNAL("clicked()"),
                     self, SLOT("adjustParameters()"))
        self.connect(self.controls.parallaxButton, SIGNAL("clicked()"),
                     self, SLOT("adjustParameters()"))
        self.connect(self.controls.leftButton, SIGNAL("clicked()"),
                     self, SLOT("slideLeft()"))
        self.connect(self.controls.rightButton, SIGNAL("clicked()"),
                     self, SLOT("slideRight()"))
    
        self.slideBy(-320)
        self.adjustParameters()
    
    @pyqtSignature("")
    def slideLeft(self):
    
        if self.iconTimeLine.state() != QTimeLine.NotRunning:
            return
        
        if self.ofs > -640:
            self.slideBy(-320)
    
    @pyqtSignature("")
    def slideRight(self):
    
        if self.iconTimeLine.state() != QTimeLine.NotRunning:
            return
        
        if self.ofs < 0:
            self.slideBy(320)
    
    @pyqtSignature("int")
    def slideBy(self, dx):
    
        iconStart = self.ofs
        iconEnd = self.ofs + dx
        self.iconTimeLine.setFrameRange(iconStart, iconEnd)
        self.iconTimeLine.start()
        
        backgroundStart = -320 - int((-320 - iconStart)/self.factor)
        backgroundEnd = -320 - int((-320 - iconEnd)/self.factor)
        self.backgroundTimeLine.setFrameRange(backgroundStart, backgroundEnd)
        self.backgroundTimeLine.start()
        
        self.ofs = iconEnd
    
    @pyqtSignature("bool")
    def setParallaxEnabled(self, p):
    
        if p:
            self.factor = 2
            self.setWindowTitle("Sliding - Parallax mode")
        else:
            self.factor = 1
            self.setWindowTitle("Sliding - Normal mode")
    
    def keyPressEvent(self, event):
    
        if event.key() == Qt.Key_Left:
            self.slideLeft()

        if event.key() == Qt.Key_Right:
            self.slideRight()
    
    @pyqtSignature("int")
    def moveIcons(self, x):
    
        i = 0
        for icon in self.icons:
            icon.setPos(320 + x+i*64, icon.pos().y())
            i += 1
    
    @pyqtSignature("int")
    def moveBackground(self, x):
    
        self.background.setPos(x, self.background.pos().y())
    
    @pyqtSignature("")
    def adjustParameters(self):
    
        speed = self.controls.speedSlider.value()
        self.iconTimeLine.setDuration(1200 - speed*10)
        self.backgroundTimeLine.setDuration(1200 - speed*10)
        self.setParallaxEnabled(self.controls.parallaxButton.isChecked())
        self.controls.leftButton.setEnabled(self.ofs > -640)
        self.controls.rightButton.setEnabled(self.ofs < 0)
class ParallaxSlide(QGraphicsView):
    def __init__(self):

        QGraphicsView.__init__(self)
        self.ofs = 0
        self.factor = 1
        self.scene = QGraphicsScene()
        self.background = None
        self.icons = []
        self.iconTimeLine = QTimeLine()
        self.backgroundTimeLine = QTimeLine()

        self.setScene(self.scene)

        self.background = self.scene.addPixmap(QPixmap(":/background.jpg"))
        self.background.setZValue(0.0)
        self.background.setPos(0, 0)

        for i in range(7):
            str = QString(":/icon%1.png").arg(i + 1)
            icon = self.scene.addPixmap(QPixmap(str))
            icon.setPos(320 + i * 64, 400)
            icon.setZValue(1.0)
            self.icons.append(icon)

        self.setFixedSize(320, 480)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.connect(self.iconTimeLine, SIGNAL("frameChanged(int)"), self,
                     SLOT("moveIcons(int)"))
        self.iconTimeLine.setCurveShape(QTimeLine.EaseInOutCurve)

        self.connect(self.backgroundTimeLine, SIGNAL("frameChanged(int)"),
                     self, SLOT("moveBackground(int)"))
        self.connect(self.backgroundTimeLine, SIGNAL("finished()"), self,
                     SLOT("adjustParameters()"))
        self.backgroundTimeLine.setCurveShape(QTimeLine.EaseInOutCurve)

        self.controls = Ui_ControlsForm()

        toolWidget = QWidget(self)
        toolWidget.setWindowFlags(Qt.Tool | Qt.WindowTitleHint)
        self.controls.setupUi(toolWidget)
        toolWidget.show()

        self.connect(self.controls.speedSlider, SIGNAL("valueChanged(int)"),
                     self, SLOT("adjustParameters()"))
        self.connect(self.controls.normalButton, SIGNAL("clicked()"), self,
                     SLOT("adjustParameters()"))
        self.connect(self.controls.parallaxButton, SIGNAL("clicked()"), self,
                     SLOT("adjustParameters()"))
        self.connect(self.controls.leftButton, SIGNAL("clicked()"), self,
                     SLOT("slideLeft()"))
        self.connect(self.controls.rightButton, SIGNAL("clicked()"), self,
                     SLOT("slideRight()"))

        self.slideBy(-320)
        self.adjustParameters()

    @pyqtSignature("")
    def slideLeft(self):

        if self.iconTimeLine.state() != QTimeLine.NotRunning:
            return

        if self.ofs > -640:
            self.slideBy(-320)

    @pyqtSignature("")
    def slideRight(self):

        if self.iconTimeLine.state() != QTimeLine.NotRunning:
            return

        if self.ofs < 0:
            self.slideBy(320)

    @pyqtSignature("int")
    def slideBy(self, dx):

        iconStart = self.ofs
        iconEnd = self.ofs + dx
        self.iconTimeLine.setFrameRange(iconStart, iconEnd)
        self.iconTimeLine.start()

        backgroundStart = -320 - int((-320 - iconStart) / self.factor)
        backgroundEnd = -320 - int((-320 - iconEnd) / self.factor)
        self.backgroundTimeLine.setFrameRange(backgroundStart, backgroundEnd)
        self.backgroundTimeLine.start()

        self.ofs = iconEnd

    @pyqtSignature("bool")
    def setParallaxEnabled(self, p):

        if p:
            self.factor = 2
            self.setWindowTitle("Sliding - Parallax mode")
        else:
            self.factor = 1
            self.setWindowTitle("Sliding - Normal mode")

    def keyPressEvent(self, event):

        if event.key() == Qt.Key_Left:
            self.slideLeft()

        if event.key() == Qt.Key_Right:
            self.slideRight()

    @pyqtSignature("int")
    def moveIcons(self, x):

        i = 0
        for icon in self.icons:
            icon.setPos(320 + x + i * 64, icon.pos().y())
            i += 1

    @pyqtSignature("int")
    def moveBackground(self, x):

        self.background.setPos(x, self.background.pos().y())

    @pyqtSignature("")
    def adjustParameters(self):

        speed = self.controls.speedSlider.value()
        self.iconTimeLine.setDuration(1200 - speed * 10)
        self.backgroundTimeLine.setDuration(1200 - speed * 10)
        self.setParallaxEnabled(self.controls.parallaxButton.isChecked())
        self.controls.leftButton.setEnabled(self.ofs > -640)
        self.controls.rightButton.setEnabled(self.ofs < 0)
class ViewMain(QMainWindow):
    """This Class Provides the Graphical Interface for Game"""

    # Use Constants To Avoid Magic Numbers
    
    # Declare stack widget names
    MAIN_PAGE = 0
    SETTINGS_PAGE = 1
    GAME_PAGE = 2
    INSTRUCTIONS_PAGE = 3
    CREDITS_PAGE = 4
    STORY_PAGE = 5
    SCORE_PAGE = 6

    finished = pyqtSignal()
    
    def __init__(self, parent=None):
        """Initialize the abstracted class instance"""
        super(ViewMain, self).__init__(parent)

        # Init Data Members
        self.gui  = Gui(self)
        self.game = None
        self.connectGui()

        self.gameWasLoaded = False
        self.useLoadWorkaround = True

        # Dictionary of Graphics Objects
        self.graphicsObjects = {}
        
        # Overlays
        self.overlays = {}
        
        self.currStackIndex = self.MAIN_PAGE
        self.gui.soundManager.playCurrMusic()
        #self.gui.soundManager.setVolume(0)
        
        # Timer initialization and setup for normal popups
        self.popupTimelineStart = QTimeLine(200)
        self.popupTimelineStart.setFrameRange(0,100)
        self.popupTimelineEnd = QTimeLine(200)
        self.popupTimelineEnd.setFrameRange(0,100)
        self.popupTimelineWait = QTimeLine()
        self.popupTimelineWait.setFrameRange(0,100)
        self.popupClue = False
        self.popupStory = False
        
        # Initialization and setup for animated popups
        self.popupAnimationOpen = QPropertyAnimation(self.gui.popup,"geometry")
        self.popupAnimationOpen.setDuration(200)
        self.popupAnimationOpen.setStartValue(QRect(0, 591, 0, 0))
        self.popupAnimationOpen.setEndValue(QRect(25, 25, 750, 450))
        self.popupAnimationClose = QPropertyAnimation(self.gui.popup,"geometry")
        self.popupAnimationClose.setDuration(200)
        self.popupAnimationClose.setStartValue(QRect(25, 25, 750, 450))
        self.popupAnimationClose.setEndValue(QRect(0, 591, 0, 0))
        self.popupAnimationWait = QTimeLine()
        
        self.toMain = False
        #self.gui.personView.centerOn(0,0)
        self.gui.mapView.centerOn(0,0)
        
########################################
### Signals and slots connected here ###
########################################

        # Connections for normal popups
        self.popupTimelineStart.frameChanged.connect(self.drawPopup)
        self.popupTimelineStart.finished.connect(self.popupWait)
        self.popupTimelineEnd.frameChanged.connect(self.erasePopup)   
        self.popupTimelineWait.finished.connect(self.enableErasePopup) 
        self.popupTimelineEnd.finished.connect(self.writeClue)
        
        # Connections for animated popups
        self.popupAnimationOpen.finished.connect(self.popupAnimationWait.start)
        self.popupAnimationWait.finished.connect(self.popupAnimationClose.start)
        self.popupAnimationClose.finished.connect(self.popupAnimationCleanup)
        self.finished.connect(self.writeStory)
    
    def connectGui(self):
        """Connect signals for Gui"""
        self.gui.actionQuit.triggered.connect(self.close)
        self.gui.quitButton.released.connect(self.close)
        self.gui.settingsButton.released.connect(self.setSettings)
        self.gui.actionSettings.triggered.connect(self.setSettings)
        self.gui.loadButton.released.connect(self.loadFileDialog)
        self.gui.actionSave_Game.triggered.connect(self.saveFileDialog)
        self.gui.doneButton.released.connect(self.goBack)
        self.gui.startButton.released.connect(self.enterName)
        self.gui.actionMain_Menu.triggered.connect(self.setMain)
        self.gui.actionHelp.triggered.connect(self.setInstructions)
        self.gui.instrButton.released.connect(self.setInstructions)
        self.gui.doneButton2.released.connect(self.goBack)
        self.gui.doneButton3.released.connect(self.goBack)
        self.gui.doneButtonScore.released.connect(self.scoreButton)
        self.gui.actionCredits.triggered.connect(self.setCredits)
        self.gui.latLongCheck.stateChanged.connect(self.latLong)
        self.gui.colorCheck.stateChanged.connect(self.colorize)
        self.gui.legendCheck.stateChanged.connect(self.legend)
        self.gui.searchButton.released.connect(self.doSearch)
        self.gui.nextButton.released.connect(self.storyButton)
        self.gui.volumeSlider.sliderMoved.connect(self.setVol)
        
    def connectGame(self):
        """Connect signals for Game"""
        self.game.places.passLoc.connect(self.addGraphicsObject)
        self.game.frameTimer.timeout.connect(self.frameUpdate)
        self.game.frameTimer.timeout.connect(self.game.story.frameTime)
        self.game.story.clueTrouble.connect(self.giveHint)

########################################
###### Custom slots defined here #######
########################################

    def setSettings(self):
        """Change to the settings page in the stack widget"""
        self.setStackWidgetIndex(self.SETTINGS_PAGE)
        
    def setInstructions(self):
        """Change to the instructions page in the stack widget"""
        self.setStackWidgetIndex(self.INSTRUCTIONS_PAGE)

    def setCredits(self):
        """Change to the credits page in the stack widget"""
        self.setStackWidgetIndex(self.CREDITS_PAGE)
        
    def goBack(self):
        """Return to the last primary page in the stack"""
        self.setStackWidgetIndex(self.gui.stackIndex)
        if self.gui.stackIndex == self.GAME_PAGE:
            self.gui.background.setPixmap(self.gui.backgroundPixmapSettings)
        else:
            self.gui.background.setPixmap(self.gui.backgroundPixmapMenu)
    
    def scoreButton(self):
        """Set widget to main menu after winning the game"""
        self.setStackWidgetIndex(self.MAIN_PAGE)
        self.gui.stackIndex = self.MAIN_PAGE
        
    def scoreWidget(self):
        """change to score widget"""
        self.game.loadScores()
        if self.game.topTen:
            text = "Congratulations "+ self.game.playerName+ \
                   ".\nYou make the Top Ten List !!"
        else:
            text = "Congratulations "+ self.game.playerName + \
                   ".\nYour score is "+ `self.game.story.score` + "!!"
        self.gui.scores.setText(text)
        self.displayHighScores()
        self.setStackWidgetIndex(self.SCORE_PAGE)
    
    def displayHighScores(self):
        """After player wins the game, we want to display
           the 10th high scores on screen
        """
        text = ""
        markCurr = 0 # Mark curr player if he made to the top ten list
        debug("len of scoreLIst is: ", len(self.game.scoreList))
        for prevPlayer in self.game.scoreList:
            prevName = prevPlayer[0]
            prevScore = prevPlayer[1]
            if (markCurr == 0 and prevName == self.game.playerName \
            and prevScore == self.game.story.score):
                markCurr = 1
                text = text + prevPlayer[0] + 40*"."  + `prevPlayer[1]` + "  *****" + "\n"
            else:
                text = text + prevPlayer[0] + 40*"."  + `prevPlayer[1]` + "\n"
        self.gui.topTenScores.setText(text)
        self.game.writeScoreToFile() 
 

    def enterName(self):
        """Name enter dialog"""
        playerName, ok = QInputDialog.getText(self, 'Enter Name Dialog', 
            'Please enter your name:')

        if ok and playerName!="":
            self.newGame()
            self.game.playerName = playerName
        else:
            pass
            
    def loadFileDialog(self):
        """pop up the loading dialog for players to choose saved file"""
        fd = QFileDialog()
        filename = fd.getOpenFileName(None, "Load Saved Game",
                                      "saves", "MapMaster Save files (*.save)")

        if isfile(filename):
            self.loadGame(filename)
        
            self.gameWasLoaded = True
            self.filename = filename
        else:
            debug("invalid file")

    def loadGame(self, filename):
        """pop up the loading dialog for players to choose saved file"""

        self.setStackWidgetIndex(self.GAME_PAGE)
        self.game = Game() 
        self.connectGame()
        self.game.load(filename)
        debug("Initializing the saved game...")
        
        
        self.overlays['latLongOverlay'] = self.addOverlay(
                    normpath("images/latOverlayNew.png"))
        self.overlays['colorOverlay'] = self.addOverlay(
                    normpath("images/colorOverlay.png"))
        self.overlays['legendOverlay'] = self.addOverlay(
                    normpath("images/legendOverlayNew.png"))

        self.gui.scoreBox.setText((str)(self.game.story.score))
        self.gui.clueView.setText(self.game.story.currClue['text'])
        self.gui.stackIndex = self.GAME_PAGE

    def saveFileDialog(self,toMain = False):
        """Dialog to save a game"""
        filename = QFileDialog.getSaveFileName(None, "Save Game", "saves", 
                                               "MapMaster Save files (*.save)")        
        if filename == "":
            return False
        else:
            if ".save" not in filename:
                debug(".save is not in the file, add one..")
                filename = filename + ".save"
            debug("correctly save data to file...",filename)
            self.game.save(filename)    
              
                        
    def newGame(self):
        """Start a new game"""
        self.gui.background.setPixmap(self.gui.backgroundPixmapSettings)
        self.setStackWidgetIndex(self.STORY_PAGE)
        self.gui.stackIndex = self.STORY_PAGE
        
        # Create game instance and start the game
        self.game = Game()
        self.connectGame()
        self.game.new()
        debug("Starting a new game")
        
        self.overlays['latLongOverlay'] = self.addOverlay(
                        normpath("images/latOverlayNew.png"))
        self.overlays['colorOverlay'] = self.addOverlay(
                        normpath("images/colorOverlay.png"))
        self.overlays['legendOverlay'] = self.addOverlay(
                        normpath("images/legendOverlayNew.png"))
        self.gui.clueView.setText(self.game.story.currClue['text'])
        self.gui.scoreBox.setText((str)(0))

        self.gameWasLoaded = False
        
    def storyButton(self):
        """Continue from the story page to the game page"""
        self.setStackWidgetIndex(self.GAME_PAGE)
        self.gui.stackIndex = self.GAME_PAGE

    def setMain(self):
        """Create a message box when player want to go back to main menu
           from the middle of the game. Make sure that player save the game.
        """
        quit_msg = "Go back to Main Menu will lose all the game, are you sure?"
        reply = QMessageBox()
        reply.setWindowTitle("Back to Main")
        reply.setText(quit_msg)
        reply.setStandardButtons(
             QMessageBox.Ok | QMessageBox.Save |  QMessageBox.Cancel)
        reply.setDefaultButton(QMessageBox.Save)
        ret = reply.exec_()
        
        if ret == QMessageBox.Ok:
            debug( "Go back to main menu" )
            self.gui.background.setPixmap(self.gui.backgroundPixmapMenu)
            self.setStackWidgetIndex(self.MAIN_PAGE)
            self.gui.stackIndex = self.MAIN_PAGE
        elif ret == QMessageBox.Cancel:
            debug("cancel back to main menu action...")
            pass
        else:
            if (self.saveFileDialog() == False):
                debug("Not save yet, go back to game...")
                pass
            else:
                debug("save and back to main menu...")
                self.gui.background.setPixmap(self.gui.backgroundPixmapMenu)
                self.setStackWidgetIndex(self.MAIN_PAGE)
                self.gui.stackIndex = self.MAIN_PAGE
        
    def setStackWidgetIndex(self, index):
        """Allow to switch between widgets."""
        if index == self.MAIN_PAGE:
            self.gui.background.setPixmap(self.gui.backgroundPixmapMenu)
        else:
            self.gui.background.setPixmap(self.gui.backgroundPixmapSettings)
    
        self.gui.stackedWidget.setCurrentIndex(index)
        self.currStackIndex = index
        self.gui.soundManager.switchSongs(index)
    
    def latLong(self):
        """Turn on/off latitude graphic overlays in the mapView"""
        if self.gui.latLongCheck.isChecked():
            debug("Lat/long overlay on")
        else:
            debug("Lat/long overlay off")
        self.overlays['latLongOverlay'].setVisible(
                                        self.gui.latLongCheck.isChecked())
    
    def colorize(self):
        """Turn on/off color coding graphic overlays in the mapView"""
        if self.gui.colorCheck.isChecked():
            debug("Color overlay on")
        else:
            debug("Color overlay off")
        self.overlays['colorOverlay'].setVisible(
                                        self.gui.colorCheck.isChecked())
                                        
    def legend(self):
        """Turn on/off legend graphic overlays in the mapView"""
        if self.gui.legendCheck.isChecked():
            debug("Legend overlay on")
        else:
            debug("Legend overlay off")
        self.overlays['legendOverlay'].setVisible(
                                        self.gui.legendCheck.isChecked())

    def setVol(self):
        """Set volumn level for the game"""
        self.gui.soundManager.setVolume(self.gui.volumeSlider.sliderPosition())
        
    def doSearch(self):
        """Begins searching for a clue"""
        self.popupClue = True
        self.popupMessage("Searching...", 2*ONE_SECOND)
    
    def writeClue(self):
        """Handles the result of searching for a clue"""
        self.popupStory = False
        if self.popupClue:
            clueResult = self.game.story.searchForClue(
                                        self.game.character.getCenter())
            self.handleClueResult(clueResult[0], clueResult[1])
            self.popupClue = False
            if clueResult[0] == 'ClueFound':
                self.popupMessageAnimated(
                        'You found a clue!\n' + clueResult[1], 4*ONE_SECOND)
                self.gui.soundManager.playSound("success")
            elif clueResult[0] == 'ClueFailed':
                self.popupMessage(clueResult[1], 2*ONE_SECOND)
                self.gui.soundManager.playSound("failure")
            elif clueResult[0] == 'GameOver':
                self.popupMessage(clueResult[1], 5*ONE_SECOND) 
                self.gui.soundManager.playSound("victory")
                QTimer.singleShot(4*ONE_SECOND, self.scoreWidget)
            else:
                None

    def writeStory(self):
        """Handles drawing story"""
        if self.game.story.currClue['story'] != 'none':
            self.popupStory = True
            self.popupMessage(self.game.story.currClue['story'], 5*ONE_SECOND)
           
    def drawPopup(self, value):
        """Draws the popup to the screen"""
        debug("Called drawPopup")
        if self.popupStory:
            self.gui.popupStoryImage.setOpacity(value/100.0)
        else:
            self.gui.popupImage.setOpacity(value/100.0)
        self.gui.popupText.setOpacity(value/100.0)
        
    def enableErasePopup(self):
        """Starts the timeline for erasePopup"""
        debug("Enabled erase popup")
        self.popupTimelineEnd.start()
        
    def erasePopup(self, value):
        """Erases the popup from the screen"""
        debug("Called erase popup")
        if self.popupStory:
            self.gui.popupStoryImage.setOpacity(1-(value/100.0))
        else:
            self.gui.popupImage.setOpacity(1-(value/100.0))
        self.gui.popupText.setOpacity(1-(value/100.0))
        
    def popupWait(self):
        """Keeps the popup on the screeen"""
        debug("Entered popupWait")
        self.popupTimelineWait.start()
        
    def popupMessageAnimated(self, text, time):
        """Uses an animated popup to display text for some time"""
        self.gui.popupText.setPlainText('')
        self.gui.popup.setGeometry(QRect(0, 591, 0, 0))
        self.gui.popupImage.setOpacity(1)
        self.popupAnimationWait.setDuration(time)
        self.popupAnimationOpen.start()
        self.gui.popupText.setPlainText(text)
        self.gui.popupText.setOpacity(1)
        
    def popupAnimationCleanup(self):
        """Returns the popup to its original state after it finishes"""
        self.gui.popupImage.setOpacity(0)
        self.gui.popupText.setOpacity(0)
        self.gui.popup.setGeometry(QRect(25, 25, 750, 450))
        self.finished.emit()
        
    def handleClueResult(self, action, text):
        """Performs the writing to gui after a clue was found"""
        if action == 'ClueFound':
            self.gui.clueView.setText(text)
            self.gui.scoreBox.setText(`self.game.story.score`)
        elif action == 'GameOver':
            self.gui.clueView.setText(text)
        else:
            None
            
    def giveHint(self):
        """If the player has been stuck on a clue, give a hint"""
        text = self.game.story.troubleFindingClue()
        self.popupMessage(text, 5*ONE_SECOND)
    
    def popupMessage(self, text, time):
        """Displays the given text for the given time in a popup"""
        self.gui.popupText.setPlainText(text)
        self.popupTimelineWait.setDuration(time)
        self.popupTimelineStart.start()
       
    def keyPressEvent(self, event):
        """Get keyboard events no matter what widget has focus"""
        if self.game and (self.gui.stackIndex == self.GAME_PAGE):
            self.game.keyPress(event)

        #Work around to make load work.
        if self.useLoadWorkaround and self.gameWasLoaded:
            self.game = Game() 
            self.connectGame()
            self.game.load(self.filename)
            
            debug("use work round")
            self.useLoadWorkaround = False

            self.overlays['latLongOverlay'] = self.addOverlay(
                    normpath("images/latOverlayNew.png"))
            self.overlays['colorOverlay'] = self.addOverlay(
                        normpath("images/colorOverlay.png"))
            self.overlays['legendOverlay'] = self.addOverlay(
                        normpath("images/legendOverlayNew.png"))
        
    
    def keyReleaseEvent(self, event):
        """Get keyboard events no matter what widget has focus"""
        if self.game and (self.gui.stackIndex == self.GAME_PAGE):
            key = event.key()
            if key==Qt.Key_Space or key==Qt.Key_Enter or key==Qt.Key_Return:
                self.doSearch()
            elif key==Qt.Key_L:
                debug('Character location is ' 
                        + `self.game.character.getCenter()`)
            else:
                self.game.keyRelease(event)
    
    def closeEvent(self, event):
        """Remapping the close event to a message box"""
        quit_msg = "Are you sure you want to quit?"
        reply = QMessageBox()
        reply.setWindowTitle("Quit Game")
        reply.setText(quit_msg)
        reply.setStandardButtons(
            QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
        reply.setDefaultButton(QMessageBox.Save)
        ret = reply.exec_()
        
        if ret == QMessageBox.Discard:
            debug("Accepting close event")
            event.accept()
        elif ret == QMessageBox.Cancel:
            event.ignore()
        else:
            if (self.saveFileDialog() == False):
                debug("Not quit yet, go back to game...")
                event.ignore()
            else:
                debug("Accepting close event")
                event.accept()

    def addGraphicsObject(self, name, xval, yval, objType):
        """Add graphics object to the person veiw and map view properly and
        leave a graphics object in ViewMain to handle it. """
        debug("Receiving passLoc")
        graphic = Graphic(xval, yval, str(name), str(objType))
        graphic.createInitial(self.gui.personView, self.gui.mapView)
        self.graphicsObjects[name] = graphic
        self.game.places.locList[str(name)].changePos.connect(
                                        self.updateGraphicsObject)
        debug("Connecting Loc to Graphic for " + name)
        
        self.game.places.locList[str(name)].emitter()
        
    def updateGraphicsObject(self, xpos, ypos, name):
        """Changes the position of the character on the screen"""
        self.graphicsObjects[name].update(xpos, ypos)
        
    def addOverlay(self, filename):
        """Adds an overlay to the map view"""
        obj = self.gui.mapView.scene.addPixmap(QPixmap(filename))
        obj.setX(-195)
        obj.setY(-250)
        obj.setVisible(False)
        return obj
        
    def frameUpdate(self):
        """One tick of the game clock sent to the character"""
        self.game.character.frameUpdate(self.game.FRAME_RATE)
Exemple #10
0
class QPageWidget(QScrollArea):
    """ The QPageWidget provides a stack widget with animated page transitions. """

    def __init__(self, parent = None, direction = "ltr", rtf = False):
        """ Creates a new QPageWidget on given parent object. 

        parent: QWidget parent
        direction: "ltr" -> Left To Right
                   "ttb" -> Top To Bottom
        rtf: Return to first, if its True it flips to the first page 
             when next page requested at the last page
        """
        # First initialize, QPageWidget is based on QScrollArea
        QScrollArea.__init__(self, parent)

        # Properties for QScrollArea
        self.setFrameShape(QFrame.NoFrame)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setWidgetResizable(True)

        # Main widget, which stores all Pages in it
        self.widget = QWidget(self)

        # Layout based on QBoxLayout which supports Vertical or Horizontal layout
        if direction == "ltr":
            self.layout = QBoxLayout(QBoxLayout.LeftToRight, self.widget)
            self.__scrollBar = self.horizontalScrollBar()
            self.__base_value = self.width
        else:
            self.layout = QBoxLayout(QBoxLayout.TopToBottom, self.widget)
            self.__scrollBar = self.verticalScrollBar()
            self.__base_value = self.height
        self.layout.setSpacing(0)
        self.layout.setMargin(0)

        # Return to first
        self.__return_to_first = rtf

        # TMP_PAGE, its using as last page in stack
        # A workaround for a QScrollArea bug
        self.__tmp_page = Page(QWidget(self.widget))
        self.__pages = [self.__tmp_page]
        self.__current = 0
        self.__last = 0

        # Set main widget
        self.setWidget(self.widget)

        # Animation TimeLine
        self.__timeline = QTimeLine()
        self.__timeline.setUpdateInterval(2)

        # Updates scrollbar position when frame changed
        self.__timeline.frameChanged.connect(lambda x: self.__scrollBar.setValue(x))

        # End of the animation
        self.__timeline.finished.connect(self._animateFinished)

        # Initialize animation
        self.setAnimation()
        self.setDuration()

    def _animateFinished(self):
        """ Its called by TimeLine when animation finished.

        It first runs the outMethod of last Page and then the inMethod of current Page
        Finally tt gives the focus to the current page and fixes the scrollBar
        """

        # Disable other widgets
        for page in self.__pages:
            if not page == self.__pages[self.__current]:
                page.widget.setEnabled(False)

        # Run last page's outMethod if exists
        if self.__pages[self.__last].outMethod:
            self.__pages[self.__last].outMethod()

        # Run new page's inMethod if exists
        if self.__pages[self.__current].inMethod:
            self.__pages[self.__current].inMethod()

        # Give focus to the current Page
        self.__pages[self.__current].widget.setFocus()

        # Update scrollbar position for current page
        self.__scrollBar.setValue(self.__current * self.__base_value())

        # Emit currentChanged SIGNAL
        self.emit(SIGNAL("currentChanged()"))

    def event(self, event):
        """ Overrides the main event handler to catch resize events """
        # Catch Resize event
        if event.type() == QEvent.Resize:
            # Update each page size limits to mainwidget's new size
            for page in self.__pages:
                page.widget.setMinimumSize(self.size())
                page.widget.setMaximumSize(self.size())

            # Update viewport size limits to mainwidget's new size
            # It's a workaround for QScrollArea updateGeometry bug
            self.viewport().setMinimumSize(self.size())
            self.viewport().setMaximumSize(self.size())

            # Update scrollbar position for current page
            self.__scrollBar.setValue(self.__current * self.__base_value())

        # Return the Event
        return QScrollArea.event(self, event)

    def keyPressEvent(self, event):
        """ Overrides the keyPressEvent to ignore them """
        pass

    def wheelEvent(self, event):
        """ Overrides the wheelEvent to ignore them """
        pass

    def createPage(self, widget, inMethod = None, outMethod = None):
        """ Creates and adds new Page for given widget with given in/out methods.

        widget: A QWidget which is the mainwidget for this Page
        inMethod: (optional) QPageWidget triggers this method when the Page appear
        outMethod: (optional) QPageWidget triggers this method when the Page disappear
        """
        self.addPage(Page(widget, inMethod, outMethod))

    def addPage(self, page):
        """ Adds the given Page to the stack.

        page: A Page object
        """
        # First remove the last page; its __tmp_page
        self.__pages.pop()

        # Add new page
        self.__pages.append(page)
        self.layout.addWidget(page.widget)

        # Add __tmp_page to end
        self.__pages.append(self.__tmp_page)
        self.layout.addWidget(self.__tmp_page.widget)

        # Create connections for page navigation signals from new page
        self.connect(page.widget, SIGNAL("pageNext()"), self.next)
        self.connect(page.widget, SIGNAL("pagePrevious()"), self.prev)
        self.connect(page.widget, SIGNAL("setCurrent(int)"), self.setCurrent)

    def __setCurrent(self, pageNumber):
        """ Internal method to set current page index. """
        self.__last = self.__current
        self.__current = min(max(0, pageNumber), len(self.__pages) - 2)
        if pageNumber == len(self.__pages) - 1 and self.__return_to_first:
            self.__current = 0

    def setCurrent(self, pageNumber = 0):
        """ Set and flip the page with given pageNumber.

        pageNumber: index number of Page (default is 0)
        """
        self.__setCurrent(pageNumber)
        self.flipPage()

    def getCurrent(self):
        """ Returns current page index. """
        return self.__current

    def getCurrentWidget(self):
        """ Returns current page widget. """
        return self.getWidget(self.getCurrent())

    def getWidget(self, pageNumber):
        """ Returns widget for given page index 

        pageNumber: index number of Page
        """
        try:
            return self.__pages[pageNumber].widget
        except:
            return None

    def count(self):
        """ Returns number of pages. """
        return len(self.__pages) - 1

    def setAnimation(self, animation = 35):
        """ Set the transition animation with the given animation.

        animation: the number represents predefined QEasingCurves
                   List of predefined QEasingCurves can be found from:
                   http://doc.qt.nokia.com/4/qeasingcurve.html#Type-enum

                   Default is QEasingCurve::InOutBack (35)
        """
        self.__animation = animation
        self.__timeline.setEasingCurve(QEasingCurve(self.__animation))

    def setDuration(self, duration = 400):
        """ Set the transition duration.

        duration: duration time in ms
        """
        self.__duration = duration
        self.__timeline.setDuration(self.__duration)

    def flipPage(self, direction=0):
        """ Flip the page with given direction.

        direction: can be -1, 0 or +1
                   -1: previous page (if exists)
                    0: just flip to current page
                   +1: next page (if exists)
        """
        # Enable all widgets
        for page in self.__pages:
            page.widget.setEnabled(True)

        # Check given direction
        direction = direction if direction == 0 else max(min(1, direction), -1)

        # If direction is equal to zero no need to re-set current
        if not direction == 0:
            self.__setCurrent(self.__current + direction)

        # If last page is different from new page, flip it !
        if not self.__last == self.__current:
            self.__timeline.setFrameRange(self.__scrollBar.value(), self.__current * self.__base_value())
            self.__timeline.start()

    def next(self):
        """ Helper method to flip next page. """
        self.flipPage(1)

    def prev(self):
        """ Helper method to flip previous page. """
        self.flipPage(-1)
class ViewMain(QMainWindow):
    """This Class Provides the Graphical Interface for Game"""

    # Use Constants To Avoid Magic Numbers
    
    # Declare stack widget names
    MAIN_PAGE = 0
    SETTINGS_PAGE = 1
    GAME_PAGE = 2
    INSTRUCTIONS_PAGE = 3
    CREDITS_PAGE = 4
    STORY_PAGE = 5
    
    def __init__(self, parent=None):
        """Initialize the abstracted class instance"""
        super(ViewMain, self).__init__(parent)

        # Init Data Members
        self.gui  = Gui(self)
        self.game = None
        self.connectGui()
        self.messageFade = None

        # Dictionary of Graphics Objects
        self.graphicsObjects = {}
        
        # Overlays
        self.overlays = {}
        
        self.currStackIndex = self.MAIN_PAGE
        self.gui.soundManager.playCurrMusic()
        self.gui.soundManager.setVolume(0)
        
        self.popupTimelineStart = QTimeLine(200)
        self.popupTimelineStart.setFrameRange(0,100)
        self.popupTimelineEnd = QTimeLine(200)
        self.popupTimelineEnd.setFrameRange(0,100)
        self.popupTimelineWait = QTimeLine()
        self.popupTimelineWait.setFrameRange(0,100)
        self.popupClue = False
        
        self.toMain = False
        #self.gui.personView.centerOn(0,0)
        #self.gui.mapView.centerOn(0,0)
        
########################################
### Signals and slots connected here ###
########################################

        self.popupTimelineStart.frameChanged.connect(self.drawPopup)
        self.popupTimelineStart.finished.connect(self.popupWait)
        self.popupTimelineEnd.frameChanged.connect(self.erasePopup)   
        self.popupTimelineWait.finished.connect(self.enableErasePopup) 
    
    def connectGui(self):
        """Connect signals for Gui"""
        self.gui.actionQuit.triggered.connect(self.close)
        self.gui.quitButton.released.connect(self.close)
        self.gui.settingsButton.released.connect(self.setSettings)
        self.gui.actionSettings.triggered.connect(self.setSettings)
        self.gui.loadButton.released.connect(self.loadFileDialog)
        self.gui.actionSave_Game.triggered.connect(self.saveFileDialog)
        self.gui.doneButton.released.connect(self.goBack)
        self.gui.startButton.released.connect(self.newGame)
        self.gui.actionMain_Menu.triggered.connect(self.setMain)
        self.gui.actionHelp.triggered.connect(self.setInstructions)
        self.gui.instrButton.released.connect(self.setInstructions)
        self.gui.doneButton2.released.connect(self.goBack)
        self.gui.doneButton3.released.connect(self.goBack)
        self.gui.actionCredits.triggered.connect(self.setCredits)
        self.gui.latLongCheck.stateChanged.connect(self.latLong)
        self.gui.colorCheck.stateChanged.connect(self.colorize)
        self.gui.legendCheck.stateChanged.connect(self.legend)
        self.gui.searchButton.released.connect(self.doSearch)
        self.gui.nextButton.released.connect(self.storyButton)
        self.gui.volumeSlider.sliderMoved.connect(self.setVol)
        
    def connectGame(self):
        # character (emits when updates) , emits newpos
        # places (emits when loc added), emits loc and signal
        # - viewMain connects that signal between the location obj and 
        # - the graphics obj
        # story (emits when working on a clue for too long), emits nothing
        # story (emits signal updating search progress), emits 0-1
        # story (emits signal for message fade), emits 1-0
        self.game.places.passLoc.connect(self.addGraphicsObject)
        self.game.story.searchTime.connect(self.enableErasePopup)
        self.game.story.clueResult.connect(self.handleClueResult)
        self.game.frameTimer.timeout.connect(self.frameUpdate)

########################################
###### Custom slots defined here #######
########################################

    def setSettings(self):
        self.setStackWidgetIndex(self.SETTINGS_PAGE)
        
    def setInstructions(self):
        self.setStackWidgetIndex(self.INSTRUCTIONS_PAGE)

    def setCredits(self):
        self.setStackWidgetIndex(self.CREDITS_PAGE)
        
    def goBack(self):
        self.setStackWidgetIndex(self.gui.stackIndex)
        if self.gui.stackIndex == self.GAME_PAGE:
            self.gui.background.setPixmap(self.gui.backgroundPixmapSettings)
        else:
            self.gui.background.setPixmap(self.gui.backgroundPixmapMenu)
            #Should be something here later
    
    def loadFileDialog(self):
        
        fd = QFileDialog()
        filename = fd.getOpenFileName(None, "Load Saved Game",
                                      "saves", "MapMaster Save files (*.save)")
        
        if isfile(filename):
            self.setStackWidgetIndex(self.GAME_PAGE)
            self.game = Game() 
            self.connectGame()
            self.game.load(filename)
            debug("Initializing the saved game...")
            
            
            self.overlays['latLongOverlay'] = self.addOverlay(
                        normpath("images/latOverlay.png"))
            self.overlays['colorOverlay'] = self.addOverlay(
                        normpath("images/colorOverlay.png"))
            self.overlays['legendOverlay'] = self.addOverlay(
                        normpath("images/legendOverlay.png"))

            self.gui.scoreBox.setText((str)(self.game.story.score))
            self.gui.clueView.setText(self.game.story.currClue['text'])
            self.gui.stackIndex = self.GAME_PAGE

    def saveFileDialog(self,toMain = False):
        filename = QFileDialog.getSaveFileName(None, "Save Game", "saves", 
                                               "MapMaster Save files (*.save)")
        if filename == "":
            return False
        else:
            if ".save" not in filename:
                debug(".save is not in the file, add one..")
                filename = filename + ".save"
            debug("correctly save data to file...",filename)
            self.game.save(filename)    
               
                        
    def newGame(self):
        self.gui.background.setPixmap(self.gui.backgroundPixmapSettings)
        self.setStackWidgetIndex(self.STORY_PAGE)
        self.gui.stackIndex = self.GAME_PAGE
        
        # Create game instance and start the game
        self.game = Game()
        debug("Initialized a new game")
        self.connectGame()
        self.game.new()
        debug("Starting a new game")
        
        self.overlays['latLongOverlay'] = self.addOverlay(
                        normpath("images/latOverlay.png"))
        self.overlays['colorOverlay'] = self.addOverlay(
                        normpath("images/colorOverlay.png"))
        self.overlays['legendOverlay'] = self.addOverlay(
                        normpath("images/legendOverlay.png"))
        self.gui.clueView.setText(self.game.story.currClue['text'])
        
    def storyButton(self):
        self.setStackWidgetIndex(self.GAME_PAGE)
        
    def setMain(self):
        if (self.saveFileDialog() == False):
            pass
        else:
            self.gui.background.setPixmap(self.gui.backgroundPixmapMenu)
            self.setStackWidgetIndex(self.MAIN_PAGE)
            self.gui.stackIndex = self.MAIN_PAGE
        
    def setStackWidgetIndex(self, index):
        if index == self.MAIN_PAGE:
            self.gui.background.setPixmap(self.gui.backgroundPixmapMenu)
        else:
            self.gui.background.setPixmap(self.gui.backgroundPixmapSettings)
    
        self.gui.stackedWidget.setCurrentIndex(index)
        self.currStackIndex = index
        self.gui.soundManager.switchSongs(index)
    
    def latLong(self):
        if self.gui.latLongCheck.isChecked():
            debug("Lat/long overlay on")
        else:
            debug("Lat/long overlay off")
        self.overlays['latLongOverlay'].setVisible(
                                        self.gui.latLongCheck.isChecked())
    
    def colorize(self):
        if self.gui.colorCheck.isChecked():
            debug("Color overlay on")
        else:
            debug("Color overlay off")
        self.overlays['colorOverlay'].setVisible(
                                        self.gui.colorCheck.isChecked())
                                        
    def legend(self):
        if self.gui.legendCheck.isChecked():
            debug("Legend overlay on")
        else:
            debug("Legend overlay off")
        self.overlays['legendOverlay'].setVisible(
                                        self.gui.legendCheck.isChecked())

    def setVol(self):
        self.gui.soundManager.setVolume(self.gui.volumeSlider.sliderPosition())
        
    def doSearch(self):
        self.game.story.searchForClue(self.game.character.getCenter())
        self.popupClue = True
        self.gui.popupText.setPlainText("Searching...")
        self.popupTimelineStart.start()
        
        
    def drawPopup(self, value):
        debug("Called drawPopup")
        self.gui.popupImage.setOpacity(value/100.0)
        self.gui.popupText.setOpacity(value/100.0)
        
    def enableErasePopup(self):
        debug("Enabled erase popup")
        self.popupClue = False
        self.popupTimelineEnd.start()
        
    def erasePopup(self, value):
        debug("Called erase popup")
        self.gui.popupImage.setOpacity(1-(value/100.0))
        self.gui.popupText.setOpacity(1-(value/100.0))
        
    def popupWait(self):
        debug("Entered popupWait")
        if not self.popupClue:
            self.popupTimelineWait.start()
        
    # FIXME This needs time actions
    def handleClueResult(self, action, text):
        if action == 'ClueFound':
            #self.popupMessage("You found a clue!", 2000)
            self.gui.clueView.setText(text)
            self.gui.scoreBox.setText(`self.game.story.score`)
        elif action == 'GameOver':
            self.gui.clueView.setText(text)
        else:
            None
    
    def popupMessage(self, text, time):
        self.gui.popupText.setPlainText(text)
        self.popupTimelineWait.setDuration(time)
        self.popupTimelineStart.start()
        
    def keyPressEvent(self, event):
        """Get keyboard events no matter what widget has focus"""
        if self.game:
            self.game.keyPress(event)
    
    def keyReleaseEvent(self, event):
        """Get keyboard events no matter what widget has focus"""
        if self.game:
            key = event.key()
            if key == Qt.Key_Space or key == Qt.Key_Enter or key == Qt.Key_Return:
                self.doSearch()
            else:
                self.game.keyRelease(event)
    
    def closeEvent(self, event):
        """Remapping the close event to a message box"""
        quit_msg = "Are you sure you want to quit?"
        reply = QMessageBox()
        reply.setWindowTitle("Quit Game")
        reply.setText(quit_msg)
        reply.setStandardButtons(
            QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
        reply.setDefaultButton(QMessageBox.Save)
        ret = reply.exec_()
        
        if ret == QMessageBox.Discard:
            print "Accepting close event"
            event.accept()
        elif ret == QMessageBox.Cancel:
            event.ignore()
        else:
            if (self.saveFileDialog() == False):
                debug("Not quit yet, go back to game...")
                event.ignore()
            else:
                print "Accepting close event"
                event.accept()

    def addGraphicsObject(self, name, xval, yval, objType):
        """Add graphics object to the person veiw and map view properly and
        leave a graphics object in ViewMain to handle it. """
        debug("Receiving passLoc")
        graphic = Graphic(xval, yval, str(name), str(objType))
        graphic.createInitial(self.gui.personView, self.gui.mapView)
        self.graphicsObjects[name] = graphic
        self.game.places.locList[str(name)].changePos.connect(
                                        self.updateGraphicsObject)
        debug("Connecting Loc to Graphic for " + name)
        
        self.game.places.locList[str(name)].emitter()
        
        #self.graphicsObjects.append(graphic)
    def updateGraphicsObject(self, xpos, ypos, name):
        #debug("Updating the graphics object")
        self.graphicsObjects[name].update(xpos, ypos)
        
    def addOverlay(self, filename):
        obj = self.gui.mapView.scene.addPixmap(QPixmap(filename))
        obj.setX(-195)
        obj.setY(-250)
        obj.setVisible(False)
        return obj
        
    def frameUpdate(self):
        #debug('Frame update sent to character')
        self.game.character.frameUpdate(self.game.FRAME_RATE)