diff options
Diffstat (limited to 'examples/widgets/widgets')
-rwxr-xr-x | examples/widgets/widgets/hellogl_openglwidget_legacy.py | 289 | ||||
-rw-r--r-- | examples/widgets/widgets/tetrix.py | 499 |
2 files changed, 788 insertions, 0 deletions
diff --git a/examples/widgets/widgets/hellogl_openglwidget_legacy.py b/examples/widgets/widgets/hellogl_openglwidget_legacy.py new file mode 100755 index 000000000..c2e918671 --- /dev/null +++ b/examples/widgets/widgets/hellogl_openglwidget_legacy.py @@ -0,0 +1,289 @@ +#!/usr/bin/env python + +############################################################################ +## +## Copyright (C) 2017 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the PySide examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################ + +"""PySide2 port of the opengl/legacy/hellogl example from Qt v5.x modified to use a QOpenGLWidget to demonstrate porting from QGLWidget to QOpenGLWidget""" + +import sys +import math +from PySide2 import QtCore, QtGui, QtWidgets + +try: + from OpenGL import GL +except ImportError: + app = QtWidgets.QApplication(sys.argv) + messageBox = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical, "OpenGL hellogl", + "PyOpenGL must be installed to run this example.", + QtWidgets.QMessageBox.Close) + messageBox.setDetailedText("Run:\npip install PyOpenGL PyOpenGL_accelerate") + messageBox.exec_() + sys.exit(1) + + +class Window(QtWidgets.QWidget): + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + + self.glWidget = GLWidget() + + self.xSlider = self.createSlider(QtCore.SIGNAL("xRotationChanged(int)"), + self.glWidget.setXRotation) + self.ySlider = self.createSlider(QtCore.SIGNAL("yRotationChanged(int)"), + self.glWidget.setYRotation) + self.zSlider = self.createSlider(QtCore.SIGNAL("zRotationChanged(int)"), + self.glWidget.setZRotation) + + mainLayout = QtWidgets.QHBoxLayout() + mainLayout.addWidget(self.glWidget) + mainLayout.addWidget(self.xSlider) + mainLayout.addWidget(self.ySlider) + mainLayout.addWidget(self.zSlider) + self.setLayout(mainLayout) + + self.xSlider.setValue(170 * 16) + self.ySlider.setValue(160 * 16) + self.zSlider.setValue(90 * 16) + + self.setWindowTitle(self.tr("QOpenGLWidget")) + + def createSlider(self, changedSignal, setterSlot): + slider = QtWidgets.QSlider(QtCore.Qt.Vertical) + + slider.setRange(0, 360 * 16) + slider.setSingleStep(16) + slider.setPageStep(15 * 16) + slider.setTickInterval(15 * 16) + slider.setTickPosition(QtWidgets.QSlider.TicksRight) + + self.glWidget.connect(slider, QtCore.SIGNAL("valueChanged(int)"), setterSlot) + self.connect(self.glWidget, changedSignal, slider, QtCore.SLOT("setValue(int)")) + + return slider + + +class GLWidget(QtWidgets.QOpenGLWidget): + xRotationChanged = QtCore.Signal(int) + yRotationChanged = QtCore.Signal(int) + zRotationChanged = QtCore.Signal(int) + + def __init__(self, parent=None): + QtWidgets.QOpenGLWidget.__init__(self, parent) + + self.object = 0 + self.xRot = 0 + self.yRot = 0 + self.zRot = 0 + + self.lastPos = QtCore.QPoint() + + self.trolltechGreen = QtGui.QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) + self.trolltechPurple = QtGui.QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) + + def xRotation(self): + return self.xRot + + def yRotation(self): + return self.yRot + + def zRotation(self): + return self.zRot + + def minimumSizeHint(self): + return QtCore.QSize(50, 50) + + def sizeHint(self): + return QtCore.QSize(400, 400) + + def setXRotation(self, angle): + angle = self.normalizeAngle(angle) + if angle != self.xRot: + self.xRot = angle + self.emit(QtCore.SIGNAL("xRotationChanged(int)"), angle) + self.update() + + def setYRotation(self, angle): + angle = self.normalizeAngle(angle) + if angle != self.yRot: + self.yRot = angle + self.emit(QtCore.SIGNAL("yRotationChanged(int)"), angle) + self.update() + + def setZRotation(self, angle): + angle = self.normalizeAngle(angle) + if angle != self.zRot: + self.zRot = angle + self.emit(QtCore.SIGNAL("zRotationChanged(int)"), angle) + self.update() + + def initializeGL(self): + darkTrolltechPurple = self.trolltechPurple.darker() + GL.glClearColor(darkTrolltechPurple.redF(), darkTrolltechPurple.greenF(), darkTrolltechPurple.blueF(), darkTrolltechPurple.alphaF()) + self.object = self.makeObject() + GL.glShadeModel(GL.GL_FLAT) + GL.glEnable(GL.GL_DEPTH_TEST) + GL.glEnable(GL.GL_CULL_FACE) + + def paintGL(self): + GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) + GL.glLoadIdentity() + GL.glTranslated(0.0, 0.0, -10.0) + GL.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) + GL.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) + GL.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) + GL.glCallList(self.object) + + def resizeGL(self, width, height): + side = min(width, height) + GL.glViewport(int((width - side) / 2),int((height - side) / 2), side, side) + + GL.glMatrixMode(GL.GL_PROJECTION) + GL.glLoadIdentity() + GL.glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0) + GL.glMatrixMode(GL.GL_MODELVIEW) + + def mousePressEvent(self, event): + self.lastPos = QtCore.QPoint(event.pos()) + + def mouseMoveEvent(self, event): + dx = event.x() - self.lastPos.x() + dy = event.y() - self.lastPos.y() + + if event.buttons() & QtCore.Qt.LeftButton: + self.setXRotation(self.xRot + 8 * dy) + self.setYRotation(self.yRot + 8 * dx) + elif event.buttons() & QtCore.Qt.RightButton: + self.setXRotation(self.xRot + 8 * dy) + self.setZRotation(self.zRot + 8 * dx) + + self.lastPos = QtCore.QPoint(event.pos()) + + def makeObject(self): + genList = GL.glGenLists(1) + GL.glNewList(genList, GL.GL_COMPILE) + + GL.glBegin(GL.GL_QUADS) + + x1 = +0.06 + y1 = -0.14 + x2 = +0.14 + y2 = -0.06 + x3 = +0.08 + y3 = +0.00 + x4 = +0.30 + y4 = +0.22 + + self.quad(x1, y1, x2, y2, y2, x2, y1, x1) + self.quad(x3, y3, x4, y4, y4, x4, y3, x3) + + self.extrude(x1, y1, x2, y2) + self.extrude(x2, y2, y2, x2) + self.extrude(y2, x2, y1, x1) + self.extrude(y1, x1, x1, y1) + self.extrude(x3, y3, x4, y4) + self.extrude(x4, y4, y4, x4) + self.extrude(y4, x4, y3, x3) + + Pi = 3.14159265358979323846 + NumSectors = 200 + + for i in range(NumSectors): + angle1 = (i * 2 * Pi) / NumSectors + x5 = 0.30 * math.sin(angle1) + y5 = 0.30 * math.cos(angle1) + x6 = 0.20 * math.sin(angle1) + y6 = 0.20 * math.cos(angle1) + + angle2 = ((i + 1) * 2 * Pi) / NumSectors + x7 = 0.20 * math.sin(angle2) + y7 = 0.20 * math.cos(angle2) + x8 = 0.30 * math.sin(angle2) + y8 = 0.30 * math.cos(angle2) + + self.quad(x5, y5, x6, y6, x7, y7, x8, y8) + + self.extrude(x6, y6, x7, y7) + self.extrude(x8, y8, x5, y5) + + GL.glEnd() + GL.glEndList() + + return genList + + def quad(self, x1, y1, x2, y2, x3, y3, x4, y4): + GL.glColor(self.trolltechGreen.redF(), self.trolltechGreen.greenF(), self.trolltechGreen.blueF(), self.trolltechGreen.alphaF()) + + GL.glVertex3d(x1, y1, +0.05) + GL.glVertex3d(x2, y2, +0.05) + GL.glVertex3d(x3, y3, +0.05) + GL.glVertex3d(x4, y4, +0.05) + + GL.glVertex3d(x4, y4, -0.05) + GL.glVertex3d(x3, y3, -0.05) + GL.glVertex3d(x2, y2, -0.05) + GL.glVertex3d(x1, y1, -0.05) + + def extrude(self, x1, y1, x2, y2): + darkTrolltechGreen = self.trolltechGreen.darker(250 + int(100 * x1)) + GL.glColor(darkTrolltechGreen.redF(), darkTrolltechGreen.greenF(), darkTrolltechGreen.blueF(), darkTrolltechGreen.alphaF()) + + GL.glVertex3d(x1, y1, -0.05) + GL.glVertex3d(x2, y2, -0.05) + GL.glVertex3d(x2, y2, +0.05) + GL.glVertex3d(x1, y1, +0.05) + + def normalizeAngle(self, angle): + while angle < 0: + angle += 360 * 16 + while angle > 360 * 16: + angle -= 360 * 16 + return angle + + def freeResources(self): + self.makeCurrent() + GL.glDeleteLists(self.object, 1) + +if __name__ == '__main__': + app = QtWidgets.QApplication(sys.argv) + window = Window() + window.show() + res = app.exec_() + window.glWidget.freeResources() + sys.exit(res) diff --git a/examples/widgets/widgets/tetrix.py b/examples/widgets/widgets/tetrix.py new file mode 100644 index 000000000..9045ac7af --- /dev/null +++ b/examples/widgets/widgets/tetrix.py @@ -0,0 +1,499 @@ +#!/usr/bin/env python + +############################################################################# +## +## Copyright (C) 2013 Riverbank Computing Limited. +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the PySide examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +"""PySide2 port of the widgets/widgets/tetrix example from Qt v5.x""" + +import random + +from PySide2 import QtCore, QtGui, QtWidgets + + +NoShape, ZShape, SShape, LineShape, TShape, SquareShape, LShape, MirroredLShape = range(8) + + +class TetrixWindow(QtWidgets.QWidget): + def __init__(self): + super(TetrixWindow, self).__init__() + + self.board = TetrixBoard() + + nextPieceLabel = QtWidgets.QLabel() + nextPieceLabel.setFrameStyle(QtWidgets.QFrame.Box | QtWidgets.QFrame.Raised) + nextPieceLabel.setAlignment(QtCore.Qt.AlignCenter) + self.board.setNextPieceLabel(nextPieceLabel) + + scoreLcd = QtWidgets.QLCDNumber(5) + scoreLcd.setSegmentStyle(QtWidgets.QLCDNumber.Filled) + levelLcd = QtWidgets.QLCDNumber(2) + levelLcd.setSegmentStyle(QtWidgets.QLCDNumber.Filled) + linesLcd = QtWidgets.QLCDNumber(5) + linesLcd.setSegmentStyle(QtWidgets.QLCDNumber.Filled) + + startButton = QtWidgets.QPushButton("&Start") + startButton.setFocusPolicy(QtCore.Qt.NoFocus) + quitButton = QtWidgets.QPushButton("&Quit") + quitButton.setFocusPolicy(QtCore.Qt.NoFocus) + pauseButton = QtWidgets.QPushButton("&Pause") + pauseButton.setFocusPolicy(QtCore.Qt.NoFocus) + + startButton.clicked.connect(self.board.start) + pauseButton.clicked.connect(self.board.pause) + quitButton.clicked.connect(QtWidgets.qApp.quit) + self.board.scoreChanged.connect(scoreLcd.display) + self.board.levelChanged.connect(levelLcd.display) + self.board.linesRemovedChanged.connect(linesLcd.display) + + layout = QtWidgets.QGridLayout() + layout.addWidget(self.createLabel("NEXT"), 0, 0) + layout.addWidget(nextPieceLabel, 1, 0) + layout.addWidget(self.createLabel("LEVEL"), 2, 0) + layout.addWidget(levelLcd, 3, 0) + layout.addWidget(startButton, 4, 0) + layout.addWidget(self.board, 0, 1, 6, 1) + layout.addWidget(self.createLabel("SCORE"), 0, 2) + layout.addWidget(scoreLcd, 1, 2) + layout.addWidget(self.createLabel("LINES REMOVED"), 2, 2) + layout.addWidget(linesLcd, 3, 2) + layout.addWidget(quitButton, 4, 2) + layout.addWidget(pauseButton, 5, 2) + self.setLayout(layout) + + self.setWindowTitle("Tetrix") + self.resize(550, 370) + + def createLabel(self, text): + lbl = QtWidgets.QLabel(text) + lbl.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignBottom) + return lbl + + +class TetrixBoard(QtWidgets.QFrame): + BoardWidth = 10 + BoardHeight = 22 + + scoreChanged = QtCore.Signal(int) + + levelChanged = QtCore.Signal(int) + + linesRemovedChanged = QtCore.Signal(int) + + def __init__(self, parent=None): + super(TetrixBoard, self).__init__(parent) + + self.timer = QtCore.QBasicTimer() + self.nextPieceLabel = None + self.isWaitingAfterLine = False + self.curPiece = TetrixPiece() + self.nextPiece = TetrixPiece() + self.curX = 0 + self.curY = 0 + self.numLinesRemoved = 0 + self.numPiecesDropped = 0 + self.score = 0 + self.level = 0 + self.board = None + + self.setFrameStyle(QtWidgets.QFrame.Panel | QtWidgets.QFrame.Sunken) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + self.isStarted = False + self.isPaused = False + self.clearBoard() + + self.nextPiece.setRandomShape() + + def shapeAt(self, x, y): + return self.board[(y * TetrixBoard.BoardWidth) + x] + + def setShapeAt(self, x, y, shape): + self.board[(y * TetrixBoard.BoardWidth) + x] = shape + + def timeoutTime(self): + return 1000 / (1 + self.level) + + def squareWidth(self): + return self.contentsRect().width() / TetrixBoard.BoardWidth + + def squareHeight(self): + return self.contentsRect().height() / TetrixBoard.BoardHeight + + def setNextPieceLabel(self, label): + self.nextPieceLabel = label + + def sizeHint(self): + return QtCore.QSize(TetrixBoard.BoardWidth * 15 + self.frameWidth() * 2, + TetrixBoard.BoardHeight * 15 + self.frameWidth() * 2) + + def minimumSizeHint(self): + return QtCore.QSize(TetrixBoard.BoardWidth * 5 + self.frameWidth() * 2, + TetrixBoard.BoardHeight * 5 + self.frameWidth() * 2) + + def start(self): + if self.isPaused: + return + + self.isStarted = True + self.isWaitingAfterLine = False + self.numLinesRemoved = 0 + self.numPiecesDropped = 0 + self.score = 0 + self.level = 1 + self.clearBoard() + + self.linesRemovedChanged.emit(self.numLinesRemoved) + self.scoreChanged.emit(self.score) + self.levelChanged.emit(self.level) + + self.newPiece() + self.timer.start(self.timeoutTime(), self) + + def pause(self): + if not self.isStarted: + return + + self.isPaused = not self.isPaused + if self.isPaused: + self.timer.stop() + else: + self.timer.start(self.timeoutTime(), self) + + self.update() + + def paintEvent(self, event): + super(TetrixBoard, self).paintEvent(event) + + painter = QtGui.QPainter(self) + rect = self.contentsRect() + + if self.isPaused: + painter.drawText(rect, QtCore.Qt.AlignCenter, "Pause") + return + + boardTop = rect.bottom() - TetrixBoard.BoardHeight * self.squareHeight() + + for i in range(TetrixBoard.BoardHeight): + for j in range(TetrixBoard.BoardWidth): + shape = self.shapeAt(j, TetrixBoard.BoardHeight - i - 1) + if shape != NoShape: + self.drawSquare(painter, + rect.left() + j * self.squareWidth(), + boardTop + i * self.squareHeight(), shape) + + if self.curPiece.shape() != NoShape: + for i in range(4): + x = self.curX + self.curPiece.x(i) + y = self.curY - self.curPiece.y(i) + self.drawSquare(painter, rect.left() + x * self.squareWidth(), + boardTop + (TetrixBoard.BoardHeight - y - 1) * self.squareHeight(), + self.curPiece.shape()) + + def keyPressEvent(self, event): + if not self.isStarted or self.isPaused or self.curPiece.shape() == NoShape: + super(TetrixBoard, self).keyPressEvent(event) + return + + key = event.key() + if key == QtCore.Qt.Key_Left: + self.tryMove(self.curPiece, self.curX - 1, self.curY) + elif key == QtCore.Qt.Key_Right: + self.tryMove(self.curPiece, self.curX + 1, self.curY) + elif key == QtCore.Qt.Key_Down: + self.tryMove(self.curPiece.rotatedRight(), self.curX, self.curY) + elif key == QtCore.Qt.Key_Up: + self.tryMove(self.curPiece.rotatedLeft(), self.curX, self.curY) + elif key == QtCore.Qt.Key_Space: + self.dropDown() + elif key == QtCore.Qt.Key_D: + self.oneLineDown() + else: + super(TetrixBoard, self).keyPressEvent(event) + + def timerEvent(self, event): + if event.timerId() == self.timer.timerId(): + if self.isWaitingAfterLine: + self.isWaitingAfterLine = False + self.newPiece() + self.timer.start(self.timeoutTime(), self) + else: + self.oneLineDown() + else: + super(TetrixBoard, self).timerEvent(event) + + def clearBoard(self): + self.board = [NoShape for i in range(TetrixBoard.BoardHeight * TetrixBoard.BoardWidth)] + + def dropDown(self): + dropHeight = 0 + newY = self.curY + while newY > 0: + if not self.tryMove(self.curPiece, self.curX, newY - 1): + break + newY -= 1 + dropHeight += 1 + + self.pieceDropped(dropHeight) + + def oneLineDown(self): + if not self.tryMove(self.curPiece, self.curX, self.curY - 1): + self.pieceDropped(0) + + def pieceDropped(self, dropHeight): + for i in range(4): + x = self.curX + self.curPiece.x(i) + y = self.curY - self.curPiece.y(i) + self.setShapeAt(x, y, self.curPiece.shape()) + + self.numPiecesDropped += 1 + if self.numPiecesDropped % 25 == 0: + self.level += 1 + self.timer.start(self.timeoutTime(), self) + self.levelChanged.emit(self.level) + + self.score += dropHeight + 7 + self.scoreChanged.emit(self.score) + self.removeFullLines() + + if not self.isWaitingAfterLine: + self.newPiece() + + def removeFullLines(self): + numFullLines = 0 + + for i in range(TetrixBoard.BoardHeight - 1, -1, -1): + lineIsFull = True + + for j in range(TetrixBoard.BoardWidth): + if self.shapeAt(j, i) == NoShape: + lineIsFull = False + break + + if lineIsFull: + numFullLines += 1 + for k in range(TetrixBoard.BoardHeight - 1): + for j in range(TetrixBoard.BoardWidth): + self.setShapeAt(j, k, self.shapeAt(j, k + 1)) + + for j in range(TetrixBoard.BoardWidth): + self.setShapeAt(j, TetrixBoard.BoardHeight - 1, NoShape) + + if numFullLines > 0: + self.numLinesRemoved += numFullLines + self.score += 10 * numFullLines + self.linesRemovedChanged.emit(self.numLinesRemoved) + self.scoreChanged.emit(self.score) + + self.timer.start(500, self) + self.isWaitingAfterLine = True + self.curPiece.setShape(NoShape) + self.update() + + def newPiece(self): + self.curPiece = self.nextPiece + self.nextPiece.setRandomShape() + self.showNextPiece() + self.curX = TetrixBoard.BoardWidth // 2 + 1 + self.curY = TetrixBoard.BoardHeight - 1 + self.curPiece.minY() + + if not self.tryMove(self.curPiece, self.curX, self.curY): + self.curPiece.setShape(NoShape) + self.timer.stop() + self.isStarted = False + + def showNextPiece(self): + if self.nextPieceLabel is not None: + return + + dx = self.nextPiece.maxX() - self.nextPiece.minX() + 1 + dy = self.nextPiece.maxY() - self.nextPiece.minY() + 1 + + pixmap = QtGui.QPixmap(dx * self.squareWidth(), dy * self.squareHeight()) + painter = QtGui.QPainter(pixmap) + painter.fillRect(pixmap.rect(), self.nextPieceLabel.palette().background()) + + for int in range(4): + x = self.nextPiece.x(i) - self.nextPiece.minX() + y = self.nextPiece.y(i) - self.nextPiece.minY() + self.drawSquare(painter, x * self.squareWidth(), + y * self.squareHeight(), self.nextPiece.shape()) + + self.nextPieceLabel.setPixmap(pixmap) + + def tryMove(self, newPiece, newX, newY): + for i in range(4): + x = newX + newPiece.x(i) + y = newY - newPiece.y(i) + if x < 0 or x >= TetrixBoard.BoardWidth or y < 0 or y >= TetrixBoard.BoardHeight: + return False + if self.shapeAt(x, y) != NoShape: + return False + + self.curPiece = newPiece + self.curX = newX + self.curY = newY + self.update() + return True + + def drawSquare(self, painter, x, y, shape): + colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, + 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00] + + color = QtGui.QColor(colorTable[shape]) + painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, + self.squareHeight() - 2, color) + + painter.setPen(color.lighter()) + painter.drawLine(x, y + self.squareHeight() - 1, x, y) + painter.drawLine(x, y, x + self.squareWidth() - 1, y) + + painter.setPen(color.darker()) + painter.drawLine(x + 1, y + self.squareHeight() - 1, + x + self.squareWidth() - 1, y + self.squareHeight() - 1) + painter.drawLine(x + self.squareWidth() - 1, + y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1) + + +class TetrixPiece(object): + coordsTable = ( + ((0, 0), (0, 0), (0, 0), (0, 0)), + ((0, -1), (0, 0), (-1, 0), (-1, 1)), + ((0, -1), (0, 0), (1, 0), (1, 1)), + ((0, -1), (0, 0), (0, 1), (0, 2)), + ((-1, 0), (0, 0), (1, 0), (0, 1)), + ((0, 0), (1, 0), (0, 1), (1, 1)), + ((-1, -1), (0, -1), (0, 0), (0, 1)), + ((1, -1), (0, -1), (0, 0), (0, 1)) + ) + + def __init__(self): + self.coords = [[0,0] for _ in range(4)] + self.pieceShape = NoShape + + self.setShape(NoShape) + + def shape(self): + return self.pieceShape + + def setShape(self, shape): + table = TetrixPiece.coordsTable[shape] + for i in range(4): + for j in range(2): + self.coords[i][j] = table[i][j] + + self.pieceShape = shape + + def setRandomShape(self): + self.setShape(random.randint(1, 7)) + + def x(self, index): + return self.coords[index][0] + + def y(self, index): + return self.coords[index][1] + + def setX(self, index, x): + self.coords[index][0] = x + + def setY(self, index, y): + self.coords[index][1] = y + + def minX(self): + m = self.coords[0][0] + for i in range(4): + m = min(m, self.coords[i][0]) + + return m + + def maxX(self): + m = self.coords[0][0] + for i in range(4): + m = max(m, self.coords[i][0]) + + return m + + def minY(self): + m = self.coords[0][1] + for i in range(4): + m = min(m, self.coords[i][1]) + + return m + + def maxY(self): + m = self.coords[0][1] + for i in range(4): + m = max(m, self.coords[i][1]) + + return m + + def rotatedLeft(self): + if self.pieceShape == SquareShape: + return self + + result = TetrixPiece() + result.pieceShape = self.pieceShape + for i in range(4): + result.setX(i, self.y(i)) + result.setY(i, -self.x(i)) + + return result + + def rotatedRight(self): + if self.pieceShape == SquareShape: + return self + + result = TetrixPiece() + result.pieceShape = self.pieceShape + for i in range(4): + result.setX(i, -self.y(i)) + result.setY(i, self.x(i)) + + return result + + +if __name__ == '__main__': + + import sys + + app = QtWidgets.QApplication(sys.argv) + window = TetrixWindow() + window.show() + random.seed(None) + sys.exit(app.exec_()) |