1
2#############################################################################
3##
4## Copyright (C) 2010 velociraptor Genjix <aphidia@hotmail.com>
5## Copyright (C) 2016 The Qt Company Ltd.
6## Contact: http://www.qt.io/licensing/
7##
8## This file is part of the Qt for Python examples of the Qt Toolkit.
9##
10## $QT_BEGIN_LICENSE:BSD$
11## You may use this file under the terms of the BSD license as follows:
12##
13## "Redistribution and use in source and binary forms, with or without
14## modification, are permitted provided that the following conditions are
15## met:
16##   * Redistributions of source code must retain the above copyright
17##     notice, this list of conditions and the following disclaimer.
18##   * Redistributions in binary form must reproduce the above copyright
19##     notice, this list of conditions and the following disclaimer in
20##     the documentation and/or other materials provided with the
21##     distribution.
22##   * Neither the name of The Qt Company Ltd nor the names of its
23##     contributors may be used to endorse or promote products derived
24##     from this software without specific prior written permission.
25##
26##
27## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
38##
39## $QT_END_LICENSE$
40##
41#############################################################################
42
43from PySide2.QtWidgets import *
44from PySide2.QtGui import *
45from PySide2.QtCore import *
46
47class MovementTransition(QEventTransition):
48    def __init__(self, window):
49        super(MovementTransition, self).__init__(window, QEvent.KeyPress)
50        self.window = window
51    def eventTest(self, event):
52        if event.type() == QEvent.StateMachineWrapped and \
53          event.event().type() == QEvent.KeyPress:
54            key = event.event().key()
55            return key == Qt.Key_2 or key == Qt.Key_8 or \
56                key == Qt.Key_6 or key == Qt.Key_4
57        return False
58    def onTransition(self, event):
59        key = event.event().key()
60        if key == Qt.Key_4:
61            self.window.movePlayer(self.window.Left)
62        if key == Qt.Key_8:
63            self.window.movePlayer(self.window.Up)
64        if key == Qt.Key_6:
65            self.window.movePlayer(self.window.Right)
66        if key == Qt.Key_2:
67            self.window.movePlayer(self.window.Down)
68
69class Custom(QState):
70    def __init__(self, parent, mw):
71        super(Custom, self).__init__(parent)
72        self.mw = mw
73
74    def onEntry(self, e):
75        print(self.mw.status)
76
77class MainWindow(QMainWindow):
78    def __init__(self):
79        super(MainWindow, self).__init__()
80        self.pX = 5
81        self.pY = 5
82        self.width = 35
83        self.height = 20
84        self.statusStr = ''
85
86        database = QFontDatabase()
87        font = QFont()
88        if 'Monospace' in database.families():
89            font = QFont('Monospace', 12)
90        else:
91            for family in database.families():
92                if database.isFixedPitch(family):
93                    font = QFont(family, 12)
94        self.setFont(font)
95
96        self.setupMap()
97        self.buildMachine()
98        self.show()
99    def setupMap(self):
100        self.map = []
101        qsrand(QTime(0, 0, 0).secsTo(QTime.currentTime()))
102        for x in range(self.width):
103            column = []
104            for y in range(self.height):
105                if x == 0 or x == self.width - 1 or y == 0 or \
106                  y == self.height - 1 or qrand() % 40 == 0:
107                    column.append('#')
108                else:
109                    column.append('.')
110            self.map.append(column)
111
112    def buildMachine(self):
113        machine = QStateMachine(self)
114
115        inputState = Custom(machine, self)
116        # this line sets the status
117        self.status = 'hello!'
118        # however this line does not
119        inputState.assignProperty(self, 'status', 'Move the rogue with 2, 4, 6, and 8')
120
121        machine.setInitialState(inputState)
122        machine.start()
123
124        transition = MovementTransition(self)
125        inputState.addTransition(transition)
126
127        quitState = QState(machine)
128        quitState.assignProperty(self, 'status', 'Really quit(y/n)?')
129
130        yesTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Y)
131        self.finalState = QFinalState(machine)
132        yesTransition.setTargetState(self.finalState)
133        quitState.addTransition(yesTransition)
134
135        noTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_N)
136        noTransition.setTargetState(inputState)
137        quitState.addTransition(noTransition)
138
139        quitTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Q)
140        quitTransition.setTargetState(quitState)
141        inputState.addTransition(quitTransition)
142
143        machine.setInitialState(inputState)
144        machine.finished.connect(qApp.quit)
145        machine.start()
146
147    def sizeHint(self):
148        metrics = QFontMetrics(self.font())
149        return QSize(metrics.width('X') * self.width, metrics.height() * (self.height + 1))
150    def paintEvent(self, event):
151        metrics = QFontMetrics(self.font())
152        painter = QPainter(self)
153        fontHeight = metrics.height()
154        fontWidth = metrics.width('X')
155
156        painter.fillRect(self.rect(), Qt.black)
157        painter.setPen(Qt.white)
158
159        yPos = fontHeight
160        painter.drawText(QPoint(0, yPos), self.status)
161        for y in range(self.height):
162            yPos += fontHeight
163            xPos = 0
164            for x in range(self.width):
165                if y == self.pY and x == self.pX:
166                    xPos += fontWidth
167                    continue
168                painter.drawText(QPoint(xPos, yPos), self.map[x][y])
169                xPos += fontWidth
170        painter.drawText(QPoint(self.pX * fontWidth, (self.pY + 2) * fontHeight), '@')
171    def movePlayer(self, direction):
172        if direction == self.Left:
173            if self.map[self.pX - 1][self.pY] != '#':
174                self.pX -= 1
175        elif direction == self.Right:
176            if self.map[self.pX + 1][self.pY] != '#':
177                self.pX += 1
178        elif direction == self.Up:
179            if self.map[self.pX][self.pY - 1] != '#':
180                self.pY -= 1
181        elif direction == self.Down:
182            if self.map[self.pX][self.pY + 1] != '#':
183                self.pY += 1
184        self.repaint()
185    def getStatus(self):
186        return self.statusStr
187    def setStatus(self, status):
188        self.statusStr = status
189        self.repaint()
190    status = Property(str, getStatus, setStatus)
191    Up = 0
192    Down = 1
193    Left = 2
194    Right = 3
195    Width = 35
196    Height = 20
197
198if __name__ == '__main__':
199    import sys
200    app = QApplication(sys.argv)
201    mainWin = MainWindow()
202    sys.exit(app.exec_())
203