def drawNodes(self, target = None): '''draws the graph nodes and prints its coords''' if target: painter = QPainter(target) else: painter = QPainter(self.graph_image) node_width = 10 painter.setPen(Qt.NoPen) for node in self.graph.nextNode(): if node in self.graph.highlighted_node: if node.data is not None: node_color = self.colorPicker(node) painter.setBrush(QBrush(node_color, Qt.SolidPattern)) else: painter.setBrush(QBrush(Qt.black, Qt.SolidPattern)) painter.drawEllipse(node.x() - node_width//2, node.y() - node_width//2, node_width, node_width) nodeNo = "" if node.data is not None and 'number' in node.data.keys(): nodeNo = str(node.data['number']) + " " node_text = QStaticText(nodeNo + str(node)) painter.setPen(QPen(Qt.black, 1)) painter.drawStaticText(node.x() - 5, node.y() + 5, node_text) painter.end()
def paintEvent(self, event): p = QPainter(self) if self.scrollEnabled: self.buffer.fill(qRgba(0, 0, 0, 0)) pb = QPainter(self.buffer) pb.setPen(p.pen()) pb.setFont(p.font()) x = min(-self.scrollPos, 0) + self.leftMargin while x < self.width(): pb.drawStaticText( QPointF(x, (self.height() - self.wholeTextSize.height()) / 2) + QPoint(2, 2), self.staticText) x += self.wholeTextSize.width() #Apply Alpha Channel pb.setCompositionMode(QPainter.CompositionMode_DestinationIn) pb.setClipRect(self.width() - 15, 0, 15, self.height()) pb.drawImage(0, 0, self.alphaChannel) pb.setClipRect(0, 0, 15, self.height()) #initial situation: don't apply alpha channel in the left half of the image at all; apply it more and more until scrollPos gets positive if self.scrollPos < 0: pb.setOpacity((max(-8, self.scrollPos) + 8) / 8.0) pb.drawImage(0, 0, self.alphaChannel) p.drawImage(0, 0, self.buffer) else: x = (self.width() - self.wholeTextSize.width()) / 2 y = (self.height() - self.wholeTextSize.height()) / 2 p.drawStaticText(QPointF(x, y), self.staticText)
def paintTitle(self, painter: QPainter): text = QStaticText(self.title()) text.setTextWidth(20) half_size = QPointF( text.size().width() / 2, text.size().height() / 2 ) painter.drawStaticText(self.pos() - half_size, text)
def paintEvent(self, event): canvas = QPainter(self) if Game.state == Game.GameState.PLAY or Game.state == Game.GameState.GAMEOVER: canvas.drawImage(self.rect(), self.image, self.image.rect()) elif Game.state == Game.GameState.PAUSED: message = '<b style="font-size:40px;">PAUSED<br> Press P to play or Esc to exit<\b>' message = QtGui.QStaticText(message) message.setTextFormat(Qt.RichText) canvas.drawStaticText(Game.stateMessageBoxX, Game.stateMessageBoxY, message)
class Drawing(QWidget): def __init__(self, object): super().__init__() self.pannel = QWidget(self) self.layout = QGridLayout() self.qp = QPainter() self.sizeScreen = self.__getSize() self.coordinatePlane = None self.drawableObject = object self.initUI() def initUI(self): self.pannel.setGeometry( QRect(0, 0, self.sizeScreen[0], self.sizeScreen[1])) self.setGeometry(QRect(0, 0, self.sizeScreen[0], self.sizeScreen[1])) self.drawAxes() self.pannel.setLayout(self.layout) self.setWindowTitle('Lab 3') self.show() def drawAxes(self): self.qp.drawLine(0, 1, self.sizeScreen[0], 1) self.qp.drawLine(1, 0, 1, self.sizeScreen[1]) for i in range(100, self.sizeScreen[0], 100): self.qp.drawLine(i, 0, i, 7) self.qp.drawStaticText(i - 10, 7, QStaticText(str(i))) for i in range(100, self.sizeScreen[1], 100): self.qp.drawLine(0, i, 10, i) self.qp.drawStaticText(10, i - 10, QStaticText(str(i))) def paintEvent(self, QPaintEvent): self.drawPlane() def drawPlane(self): self.coordinatePlane = CoordinatePlane(self.size()) self.qp.begin(self) self.qp.setPen(Qt.black) self.drawAxes() self.drawableObject.draw(self.sizeScreen, self.qp) self.qp.end() def __getSize(self): h = QDesktopWidget().screenGeometry().height() - 100 w = QDesktopWidget().screenGeometry().width() - 100 return [w, h]
def paintEvent(self, e): p = QPainter(self) opt = QStyleOptionSlider() self.initStyleOption(opt) p.translate(opt.rect.x(), opt.rect.y()) p.setPen(opt.palette.windowText().color()) # tickOffset = sty.pixelMetric(QStyle.PM_SliderTickmarkOffset, opt, self.slider) available = self.style().pixelMetric(QStyle.PM_SliderSpaceAvailable, opt, self) slen = self.style().pixelMetric(QStyle.PM_SliderLength, opt, self) fudge = slen / 2 for i in range(len(self.labels)): v = opt.minimum + i pos = self.style().sliderPositionFromValue(opt.minimum, opt.maximum, v, available) + fudge # p.drawLine(pos, 0, pos, tickOffset - 2) br = p.fontMetrics().boundingRect(self.labels[i]) pos = min(max(pos, br.width()/2), available+fudge-br.width()/2) p.drawStaticText(pos - br.width()/2, 0, QStaticText(self.labels[i])) super().paintEvent(e)
class Mainframe(QWidget): def __init__(self): super().__init__() self.layout = QGridLayout() self.pannel = QWidget(self) self.qp = QPainter() self.coordinatePlane = CoordinatePlane( QDesktopWidget().availableGeometry()) self.sizeScreen = QDesktopWidget().availableGeometry() self.__setDefaultPosition() self.figures = [] self.figures = self.__figures() self.label_move_dx = QLabel("dx") self.label_move_dy = QLabel("dy") self.label_resize_xc = QLabel("xc") self.label_resize_yc = QLabel("yc") self.label_resize_kx = QLabel("kx") self.label_resize_ky = QLabel("ky") self.label_rotate_xc = QLabel("xc") self.label_rotate_yc = QLabel("yc") self.label_rotate_angle = QLabel("angle") self.label_move = QLabel("Movement") self.label_resize = QLabel("Resize") self.label_rotate = QLabel("Rotation") self.button_move = QPushButton("Move") self.button_resize = QPushButton("Resize") self.button_rotate = QPushButton("Rotate") self.button_reset = QPushButton("Reset") self.button_back = QPushButton("Back") self.button_move.clicked.connect(self.buttonMoveEvent) self.button_resize.clicked.connect(self.buttonResizeEvent) self.button_rotate.clicked.connect(self.buttonRotateEvent) self.button_back.clicked.connect(self.buttonBackEvent) self.button_reset.clicked.connect(self.buttonResetEvent) self.edit_move_dx = QDoubleSpinBox() self.edit_move_dy = QDoubleSpinBox() self.edit_resize_xc = QDoubleSpinBox() self.edit_resize_yc = QDoubleSpinBox() self.edit_resize_kx = QDoubleSpinBox() self.edit_resize_ky = QDoubleSpinBox() self.edit_rotate_xc = QDoubleSpinBox() self.edit_rotate_yc = QDoubleSpinBox() self.edit_angle = QSpinBox() self.edit_move_dx.setMaximum(self.sizeScreen.width() / 2) self.edit_move_dx.setMinimum(-1 * self.sizeScreen.width() / 2) self.edit_move_dy.setMaximum(self.sizeScreen.height() / 2) self.edit_move_dy.setMinimum(-1 * self.sizeScreen.height() / 2) self.edit_resize_xc.setMinimum(-1 * self.sizeScreen.width() / 2) self.edit_resize_xc.setMaximum(self.sizeScreen.width() / 2) self.edit_resize_yc.setMinimum(-1 * self.sizeScreen.height() / 2) self.edit_resize_yc.setMaximum(self.sizeScreen.height() / 2) self.edit_rotate_xc.setMaximum(self.sizeScreen.width()) self.edit_rotate_xc.setMinimum(0) self.edit_rotate_yc.setMaximum(self.sizeScreen.height()) self.edit_rotate_yc.setMinimum(0) self.edit_angle.setMinimum(-360) self.edit_angle.setMaximum(360) self.initUI() def __setDefaultPosition(self): self.angle = 0 self.rotation_center_x = 0 self.rotation_center_y = 0 self.radX = 40 self.radY = 40 self.astroid_heigth = 200 self.astroid_width = 200 self.rect_heigth = 400 self.rect_width = 400 self.sstate = QPoint(self.sizeScreen.width() / 2, self.sizeScreen.height() / 2) self.state = QPoint(self.sizeScreen.width() / 2, self.sizeScreen.height() / 2) self.__clearSavedState() def __clearSavedState(self): self.curRadX = None self.curRadY = None self.curAstrHeight = None self.curAstrWidth = None self.curRectH = None self.curRectWidth = None self.cur_action = None self.cur_angle = None self.cur_rotation_center_x = None self.cur_rotation_center_y = None self.cur_radX = None self.cur_radY = None self.cur_astroid_heigth = None self.cur_astroid_width = None self.cur_rect_heigth = None self.cur_rect_width = None self.cur_state = None def __setPreviousPosition(self): if (self.cur_action == None): self.__setDefaultPosition() return else: if self.cur_action == Action.MOVE: for i in self.figures: i.move(-self.cur_dx, -self.cur_dy) self.repaint() elif self.cur_action == Action.ROTATE: for i in self.figures: i.rotate(self.cur_rotation_center_x, self.cur_rotation_center_y, -self.cur_angle) self.repaint() elif self.cur_action == Action.SCALE: # if (self.cur_kx != 0 and self.cur_ky != 0): # for i in self.figures: self.figures[0].scale1(self.curRadX, self.curRadY, self.state.x(), self.state.y(), self.cur_kx, self.cur_ky) self.figures[1].scale1(self.curRectH, self.curRectWidth, self.state.x(), self.state.y(), self.cur_kx, self.cur_ky) self.figures[2].scale1(self.curAstrHeight, self.curAstrWidth, self.state.x(), self.state.y(), self.cur_kx, self.cur_ky) # i.scale(1 / self.cur_kx, 1 / self.cur_ky, self.cur_scale_xc, self.cur_scale_yc) self.repaint() # else: # self.__showErrorMessage("Невозможно выполнить действие!") self.__clearSavedState() def __showErrorMessage(self, message): error_message = QErrorMessage(self) error_message.setWindowTitle("Error") error_message.showMessage(message) def buttonResetEvent(self): self.figures = self.__figures() self.__clearSavedState() self.__setDefaultPosition() self.repaint() def buttonBackEvent(self): if self.cur_action != None: self.__setPreviousPosition() self.repaint() def buttonResizeEvent(self): self.kx = self.edit_resize_kx.value() self.ky = self.edit_resize_ky.value() if self.kx == 1 and self.ky == 1: return self.scale_xc = self.edit_resize_xc.value() self.scale_yc = self.edit_resize_yc.value() self.cur_action = Action.SCALE self.__saveScale() for i in self.figures: i.scale(self.kx, self.ky, self.scale_xc, self.scale_yc) self.repaint() def buttonRotateEvent(self): self.angle = self.edit_angle.value() if self.angle == 0: return self.rotation_center_x = self.edit_rotate_xc.value() self.rotation_center_y = self.edit_rotate_yc.value() self.cur_action = Action.ROTATE self.__saveRotation() for i in self.figures: i.rotate(self.rotation_center_x, self.rotation_center_y, self.angle) self.repaint() def buttonMoveEvent(self): self.new_offset_x = self.edit_move_dx.value() self.new_offset_y = self.edit_move_dy.value() if self.new_offset_x == 0 and self.new_offset_y == 0: return self.__saveMovement() self.cur_action = Action.MOVE for i in self.figures: i.move(self.new_offset_x, self.new_offset_y) self.repaint() def initUI(self): self.pannel.setGeometry( QRect(self.sizeScreen.width() - 200, 40, 200, self.sizeScreen.height() / 2)) self.setGeometry(0, 0, self.sizeScreen.width(), self.sizeScreen.height()) self.__addWidgets() self.pannel.setLayout(self.layout) self.setWindowTitle('Lab 2') self.show() def __addWidgets(self): self.layout.addWidget(self.label_move, 0, 0) self.layout.addWidget(self.edit_move_dx, 1, 0) self.layout.addWidget(self.label_move_dx, 1, 1) self.layout.addWidget(self.edit_move_dy, 2, 0) self.layout.addWidget(self.label_move_dy, 2, 1) self.layout.addWidget(self.button_move, 3, 0) self.layout.addWidget(self.label_resize, 4, 0) self.layout.addWidget(self.edit_resize_xc, 5, 0) self.layout.addWidget(self.label_resize_xc, 5, 1) self.layout.addWidget(self.edit_resize_yc, 6, 0) self.layout.addWidget(self.label_resize_yc, 6, 1) self.layout.addWidget(self.edit_resize_kx, 7, 0) self.layout.addWidget(self.label_resize_kx, 7, 1) self.layout.addWidget(self.edit_resize_ky, 8, 0) self.layout.addWidget(self.label_resize_ky, 8, 1) self.layout.addWidget(self.button_resize, 9, 0) self.layout.addWidget(self.label_rotate, 10, 0) self.layout.addWidget(self.edit_rotate_xc, 11, 0) self.layout.addWidget(self.label_rotate_xc, 11, 1) self.layout.addWidget(self.edit_rotate_yc, 12, 0) self.layout.addWidget(self.label_rotate_yc, 12, 1) self.layout.addWidget(self.edit_angle, 14, 0) self.layout.addWidget(self.label_rotate_angle, 14, 1) self.layout.addWidget(self.label_rotate, 15, 0) self.layout.addWidget(self.button_rotate, 16, 0) self.layout.addWidget(self.button_back, 17, 0) self.layout.addWidget(self.button_reset, 18, 0) def paintEvent(self, e): self.drawPlane() def drawAxes(self): oneUnit = self.coordinatePlane.oneUnit() self.qp.drawLine(1, 0, 1, self.sizeScreen.height()) self.qp.drawLine(0, 1, self.sizeScreen.width(), 1) for i in range(100, self.sizeScreen.height(), 100): self.qp.drawLine(0, i, 10, i) self.qp.drawStaticText(12, i - 7, QStaticText(str(i))) for i in range(100, self.sizeScreen.width(), 100): self.qp.drawLine(i, 0, i, 10) self.qp.drawStaticText(i - 10, 12, QStaticText(str(i))) self.qp.drawStaticText(7, 7, QStaticText(str(0))) def drawPlane(self): self.qp.begin(self) self.qp.setPen(Qt.black) self.drawAxes() self.qp.drawPoint(self.rotation_center_x, self.rotation_center_y) for i in self.figures: p = i.draw(self.coordinatePlane) self.qp.drawPath(p) self.qp.end() def __saveMovement(self): self.cur_dx = self.new_offset_x self.cur_dy = self.new_offset_y self.cur_state = self.state def __saveRotation(self): self.cur_angle = self.angle self.cur_rotation_center_x = self.rotation_center_x self.cur_rotation_center_y = self.rotation_center_y def __saveScale(self): self.curRadX = self.figures[0].x_height self.curRadY = self.figures[0].y_height self.curAstrHeight = self.astroid_heigth self.curAstrWidth = self.astroid_width self.curRectH = self.rect_heigth self.curRectWidth = self.rect_width self.state.setX(self.figures[0].center_x) self.state.setY(self.figures[0].center_y) self.cur_kx, self.cur_ky = self.kx, self.ky self.cur_scale_xc, self.cur_scale_yc = self.scale_xc, self.scale_yc def __figures(self): figures = [] circle = MyCircle(self.radX, self.radY, self.sstate.x(), self.sstate.y()) rect = Rect(self.sstate.x(), self.sstate.y(), self.rect_heigth, self.rect_width) ast = Astroid(self.sstate.x(), self.sstate.y(), self.astroid_heigth, self.astroid_width) figures.append(circle) figures.append(rect) figures.append(ast) return figures
class Drawing(QWidget): def __init__(self, figures, set1, set2): super().__init__() self.pannel = QWidget(self) self.layout = QGridLayout() self.qp = QPainter() self.sizeScreen = [QDesktopWidget().availableGeometry().width() - 100, QDesktopWidget().availableGeometry().height() - 100] self.coordinatePlane = None self.kx = 1 self.ky = 1 self.dx = 0 self.dy = 0 self.figures = figures self.set1 = set1 self.set2 = set2 self.initUI() def setFigures(self, f): self.figures = f def paintEvent(self, QPaintEvent): self.drawPlane() def addFigure(self, twoCircles): self.figures.append(twoCircles) def initUI(self): self.pannel.setGeometry(0, 0, self.sizeScreen[0], self.sizeScreen[1]) self.setGeometry(0, 0, self.sizeScreen[0], self.sizeScreen[1]) self.drawAxes() self.pannel.setLayout(self.layout) self.setWindowTitle('Lab 1') self.show() def drawPlane(self): self.coordinatePlane = CoordinatePlane(self.size()) self.qp.begin(self) self.qp.setPen(Qt.black) self.drawAxes() self.__drawPoints() for i in self.figures: random_color = QColor(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) while random_color == (255, 255, 255): random_color = QColor(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) newPen = QPen() newPen.setColor(random_color) self.qp.setPen(newPen) i.draw(self.qp, self.kx, self.ky, self.dx, self.dy, self.sizeScreen) self.qp.end() def __drawPoints(self): color = Qt.red newPen = QPen() newPen.setColor(color) self.qp.setPen(newPen) for i in range(len(self.set1)): point = QPoint((self.set1[i].get_x() + self.dx) * self.kx, self.sizeScreen[1] - (self.set1[i].get_y() + self.dy) * self.ky) self.qp.drawEllipse(point, 5, 5) point = QPoint(round(point.x() - 20), round((point.y() - 20))) text = "" text += str(self.set1[i].get_x()) + "," + str(self.set1[i].get_y()) self.qp.drawStaticText(point, QStaticText(text)) color = Qt.green newPen = QPen() newPen.setColor(color) self.qp.setPen(newPen) for i in range(len(self.set2)): point = QPoint((self.set2[i].get_x() + self.dx) * self.kx, self.sizeScreen[1] - (self.set2[i].get_y() + self.dy) * self.ky) self.qp.drawEllipse(point, 5, 5) point = QPoint(round(point.x() - 20), round((point.y() - 20))) text = "" text += str(self.set2[i].get_x()) + "," + str(self.set2[i].get_y()) self.qp.drawStaticText(point, QStaticText(text)) def __randomColor(self): return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) def drawAxes(self): xMax, yMax, xMin, yMin = self.__getBounds() resize = 10 if abs(xMax) < 1 or abs(yMax) < 1 or abs(xMin) < 1 or abs(yMin) < 1: resize = 0.5 if abs(xMax) / 10 < 1 or abs(yMax) / 10 < 1 or abs(xMin) / 10 < 1 or abs(yMin) / 10 < 1: resize = 0.1 xMin -= resize yMin -= resize self.dx = -1 * xMin self.dy = -1 * yMin intervalX = (xMax + resize) - xMin intervalY = (yMax + resize) - yMin k = min((self.sizeScreen[0] - resize) / (intervalX), (self.sizeScreen[1] - resize) / (intervalY)) self.kx = k self.ky = k stepX = (intervalX / 10) stepY = (intervalY / 10) self.qp.drawLine(1, 0, 1, self.sizeScreen[1]) self.qp.drawLine(0, self.sizeScreen[1] - 2, self.sizeScreen[0], self.sizeScreen[1] - 2) i = yMin + stepY while i <= self.sizeScreen[1] / self.ky: self.qp.drawLine(0, self.sizeScreen[1] - (i + self.dy) * self.ky, 10, self.sizeScreen[1] - (i + self.dy) * self.ky) self.qp.drawStaticText(12, self.sizeScreen[1] - (i + self.dy) * self.ky, QStaticText(str(round(i, 2)))) i += stepY i = xMin + stepX while i <= self.sizeScreen[0] / self.kx: self.qp.drawLine((i + self.dx) * self.kx, self.sizeScreen[1] - 1, (i + self.dx) * self.kx, self.sizeScreen[1] - 11) self.qp.drawStaticText((i + self.dx) * self.kx, self.sizeScreen[1] - 25, QStaticText(str(round(i, 2)))) i += stepX # for i in range(yMin + stepY, self.sizeScreen[1], stepY): # self.qp.drawLine(0, self.sizeScreen[1] - (i + self.dy) * self.ky, 10, self.sizeScreen[1] - (i + self.dy) * self.ky) # self.qp.drawStaticText(12, self.sizeScreen[1] - (i + self.dy) * self.ky, QStaticText(str(i))) # # for i in range(xMin + stepX, self.sizeScreen[0], stepX): # self.qp.drawLine((i + self.dx) * self.kx, self.sizeScreen[1] - 1, (i + self.dx) * self.kx, self.sizeScreen[1] - 11) # self.qp.drawStaticText((i + self.dx) * self.kx, self.sizeScreen[1] - 25, QStaticText(str(i))) # self.qp.drawStaticText(7, 7, QStaticText(str(start))) def __getBounds(self): xMax, yMax, xMin, yMin = None, None, None, None for i in range(len(self.figures)): c1, c2, r1, r2 = self.figures[i].getCircles() xMaxTmp = max((c1.get_x() + r1), (c2.get_x() + r2)) xMinTmp = min((c1.get_x() - r1), (c2.get_x() - r2)) yMaxTmp = max((c1.get_y() + r1), (c2.get_y() + r2)) yMinTmp = min((c1.get_y() - r1), (c2.get_y() - r2)) # xMaxTmp = max(round(c1.get_x() + r1), round(c2.get_x() + r2)) # xMinTmp = min(round(c1.get_x() - r1), round(c2.get_x() - r2)) # yMaxTmp = max(round(c1.get_y() + r1), round(c2.get_y() + r2)) # yMinTmp = min(round(c1.get_y() - r1), round(c2.get_y() - r2)) if xMax == None: xMax = xMaxTmp else: xMax = max(xMax, xMaxTmp) if yMax == None: yMax = yMaxTmp else: yMax = max(yMax, yMaxTmp) if xMin == None: xMin = xMinTmp else: xMin = min(xMin, xMinTmp) if yMin == None: yMin = yMinTmp else: yMin = min(yMin, yMinTmp) return xMax, yMax, xMin, yMin
class Ui_MainWindow(QMainWindow): def __init__(self): super(Ui_MainWindow, self).__init__() self.setObjectName("MainWindow") self.resize(Game.screenWidth, Game.screenHeight) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("res/Instructions-icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.setWindowIcon(icon) self.menubar = QtWidgets.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") self.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.actionExit = QtWidgets.QAction(self) self.actionExit.setObjectName("actionExit") self.menuFile.addAction(self.actionExit) self.menubar.addAction(self.menuFile.menuAction()) self.actionExit.triggered.connect(self.closeEvent) _translate = QtCore.QCoreApplication.translate self.menuFile.setTitle(_translate("MainWindow", "File")) self.actionExit.setText(_translate("MainWindow", "Exit")) self.actionExit.setShortcut(_translate("MainWindow", "Ctrl+Q")) self.image = QImage(self.size(), QImage.Format_RGB32) self.image.fill(Qt.white) pen = QPen() pen.setBrush(QtGui.QBrush(Game.angleLineColor)) self.painter = QPainter(self.image) self.painter.setPen(pen) self.stateMessage = '' # self.hitSound = QtGui. self.homeUi() def homeUi(self): Game.state = Game.GameState.INTRO self.removeAllPaint() self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.centralwidget.setAutoFillBackground(False) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem, 2, 1, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem1, 1, 2, 1, 1) self.label = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setFamily("Orbitron") font.setPointSize(28) font.setBold(True) font.setWeight(75) self.label.setFont(font) self.label.setFrameShadow(QtWidgets.QFrame.Raised) self.label.setAlignment(QtCore.Qt.AlignCenter) self.label.setObjectName("label") self.gridLayout.addWidget(self.label, 1, 1, 1, 1) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem2, 1, 0, 1, 1) self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setEnabled(True) font = QtGui.QFont() font.setPointSize(16) self.pushButton.setFont(font) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("res/Instructions-icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.pushButton.setIcon(icon) self.pushButton.setObjectName("pushButton") self.gridLayout.addWidget(self.pushButton, 4, 1, 1, 1) self.pushButton.pressed.connect(self.insUi) spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem3, 0, 1, 1, 1) spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem4, 5, 1, 1, 1) self.playButton = QtWidgets.QPushButton(self.centralwidget) font = QtGui.QFont() font.setPointSize(16) self.playButton.setFont(font) self.playButton.setAutoFillBackground(False) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("res/Play-icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.playButton.setIcon(icon1) self.playButton.setObjectName("playButton") self.gridLayout.addWidget(self.playButton, 3, 1, 1, 1) self.playButton.pressed.connect(self.gameTypeUi) self.setCentralWidget(self.centralwidget) self.retranslateHomeUi() QtCore.QMetaObject.connectSlotsByName(self) def retranslateHomeUi(self): _translate = QtCore.QCoreApplication.translate self.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label.setText(_translate("MainWindow", "HIT ME IF YOU CAN")) self.pushButton.setText(_translate("MainWindow", "Instructions")) self.playButton.setText(_translate("MainWindow", "Play Now")) self.show() def gameTypeUi(self): self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setAutoFillBackground(False) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.p2c = QtWidgets.QPushButton(self.centralwidget) font = QtGui.QFont() font.setPointSize(12) self.p2c.setFont(font) self.p2c.setObjectName("p2c") self.gridLayout.addWidget(self.p2c, 5, 3, 1, 1) self.p2c.pressed.connect(self.p2cSelection) self.p2p = QtWidgets.QPushButton(self.centralwidget) font = QtGui.QFont() font.setPointSize(12) self.p2p.setFont(font) self.p2p.setObjectName("p2p") self.gridLayout.addWidget(self.p2p, 5, 1, 1, 1) self.p2p.pressed.connect(self.p2pSelection) spacerItem = QtWidgets.QSpacerItem(20, 100, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) self.gridLayout.addItem(spacerItem, 6, 1, 1, 3) spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) self.gridLayout.addItem(spacerItem1, 1, 1, 1, 3) self.gameType = QtWidgets.QLabel(self.centralwidget) self.gameType.setTextFormat(QtCore.Qt.RichText) self.gameType.setAlignment(QtCore.Qt.AlignCenter) self.gameType.setObjectName("gameType") self.gridLayout.addWidget(self.gameType, 0, 0, 1, 5) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem2, 5, 2, 1, 1) spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem3, 5, 0, 1, 1) spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem4, 5, 4, 1, 1) self.setCentralWidget(self.centralwidget) self.retranslateGameTypeUi() QtCore.QMetaObject.connectSlotsByName(self) def retranslateGameTypeUi(self): _translate = QtCore.QCoreApplication.translate self.setWindowTitle(_translate("MainWindow", "MainWindow")) self.p2c.setText(_translate("MainWindow", "With Computer")) self.p2p.setText(_translate("MainWindow", "Two Player")) self.gameType.setText( _translate("MainWindow", "<b style=\'font-size:25px\' >Choose The Game Type<b>")) def p2pSelection(self): Game.type = Game.Type.P2P self.playUi() def p2cSelection(self): Game.type = Game.Type.P2C self.playUi() def insUi(self): Game.state = Game.GameState.INSTRUCT self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setAutoFillBackground(False) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.backButton = QtWidgets.QPushButton(self.centralwidget) font = QtGui.QFont() font.setPointSize(14) self.backButton.setFont(font) self.backButton.setObjectName("backButton") self.gridLayout.addWidget(self.backButton, 8, 1, 1, 1) self.backButton.pressed.connect(self.homeUi) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem, 8, 0, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem1, 8, 2, 1, 1) spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) self.gridLayout.addItem(spacerItem2, 6, 0, 1, 3) self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget) font = QtGui.QFont() font.setPointSize(16) self.plainTextEdit.setFont(font) self.plainTextEdit.setReadOnly(True) self.plainTextEdit.setObjectName("plainTextEdit") self.gridLayout.addWidget(self.plainTextEdit, 3, 0, 1, 3) spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) self.gridLayout.addItem(spacerItem3, 2, 0, 1, 3) self.label = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(18) font.setBold(True) font.setWeight(75) self.label.setFont(font) self.label.setFrameShape(QtWidgets.QFrame.NoFrame) self.label.setAlignment(QtCore.Qt.AlignCenter) self.label.setObjectName("label") self.gridLayout.addWidget(self.label, 0, 0, 1, 3) self.setCentralWidget(self.centralwidget) self.retranslateInsUi() QtCore.QMetaObject.connectSlotsByName(self) def retranslateInsUi(self): _translate = QtCore.QCoreApplication.translate self.setWindowTitle(_translate("MainWindow", "MainWindow")) self.backButton.setText(_translate("MainWindow", "Back to Mainmenu")) ins = ''' 1. Each of the players will have his turn. 2. Player 1 can tune angle and speed by Key A and D. 3. Player 2 can use Key Left Arrow and Right Arrow to do that. 4. Space Key is used to select an angle or speed and advance. 5. The opponent has a few time to take his position also using A and D or Right and Left Arrow Button depending on his playing side. 6. Player who can hit his opponent gains a point. 7. Press P to pause the game and then Esc to get to the Mainmenu or again P to resume 8. Player gaining 5 points first, is the winner. ''' self.plainTextEdit.setPlainText(_translate("MainWindow", ins)) self.label.setText(_translate("MainWindow", "INSTRUCTION")) self.show() def playUi(self): Game.state = Game.GameState.PLAY self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setAutoFillBackground(False) self.centralwidget.setObjectName("centralwidget") self.painter.fillRect(0, Game.screenHeight - Game.fieldHeight, Game.screenWidth, Game.fieldHeight, Game.fieldColor) self.painter.fillRect(Game.barPosX, Game.barPosY, Game.barWidth, Game.barHeight, Game.fieldColor) self.setCentralWidget(self.centralwidget) self.show() global player1 global player2 player1 = Player((Game.player1limitX[0] + Game.player1limitX[1]) / 2) player2 = Player((Game.player2limitX[0] + Game.player2limitX[1]) / 2) # Main GameLoop Begins Game.turn = Game.Turn.P1 self.startToMove() # Main GameLoop Ends def startToMove(self): Game.action = Game.Action.MOVE stone.gotoP() self.stateMessage = 'Take your position' self.paintField() QTimer.singleShot(2000, self.switchMoveToThrow) if Game.type == Game.Type.P2C and Game.turn == Game.Turn.P1: player2.playerX = random.randint(Game.player2limitX[0], Game.player2limitX[1]) self.paintField() # ----------------------------- # # # # for development purpose # # # # ----------------------------- # # # else: # player1.playerX = random.randint(Game.player1limitX[0], Game.player1limitX[1]) ## # QTimer.singleShot(5, self.switchMoveToThrow) # Till here # def switchMoveToThrow(self): self.stateMessage = 'Aim and Throw' Game.action = Game.Action.SET_ANGLE_FORCE angle_line.gotoStone() self.paintField() if Game.type == Game.Type.P2C and Game.turn == Game.Turn.P2: Game.action = Game.Action.THROW # target = player2.playerX - player1.playerX# - Game.playerHeight / 2 # bar_dist = player2.playerX - Game.barPosX # print(target - bar_dist, bar_dist) # computer_input = [[target, bar_dist]] #to feed the model imageCrop = 300 imageResize = (80, 30) computer_input = qimage2ndarray.byte_view(self.image)[imageCrop:] computer_input = cv2.resize(computer_input, imageResize) # cv2.imshow(' ', computer_input) # cv2.waitKey(0) # cv2.destroyAllWindows() computer_input = computer_input.reshape((1, ) + computer_input.shape) computer_input = computer_input / 255 computer_output = Game.computer.predict(computer_input) angle = computer_output[0][0] velocity = computer_output[0][1] # - 2 # angle_line.current_angle = angle angle_line.current_vel = velocity # print(angle, velocity) self.throw() self.paintField() angle_line.current_vel = Game.defaultForceLen # ----------------------------- # # # # for development purpose # # # # ----------------------------- # # Game.data.append([target, bar_dist, angle, a_velocity]) # Game.dataCount += 1 # # if Game.dataCount >= 100: # x_train = [] # y_train = [] # # for i in Game.data: # x_train.append([i[0], i[2]]) # y_train.append([i[3]]) # # x_train = numpy.array(x_train) # y_train = numpy.array(y_train) # # x_train = tf.keras.utils.normalize(x_train) # y_train = y_train / 110 # # Game.computer_vel.fit(x_train, y_train, epochs=3) # # Game.data = [] # Game.dataCount = 0 # # else: # Game.action = Game.Action.THROW # self.throw() # Till here # def throw(self): prevX = stone.stoneX prevY = stone.stoneY v0 = angle_line.getVel() theta = angle_line.current_angle * math.pi / 180 cos_theta = math.cos(theta) sin_theta = math.sin(theta) g = 9.8 ground = Game.screenHeight - Game.fieldHeight - Game.stoneWidth t = 0 if Game.turn == Game.Turn.P1: player = player1 opponent = player2 else: player = player2 opponent = player1 while stone.stoneY < ground: if Game.state == Game.GameState.PAUSED: QtTest.QTest.qWait(1000) continue x_ = v0 * t * cos_theta y_ = v0 * t * sin_theta - 0.5 * g * t * t # if stone.stoneY >= opponent.playerY: # print('distance travelled = ', x_) stone.stoneX = prevX + x_ stone.stoneY = prevY - y_ if stone.stoneY > ground: stone.stoneY = ground # unsuccessful self.stateMessage = 'Missed...' thread.start_new_thread( self.playMusic, ('res\\Woosh-Mark_DiAngelo-4778593.wav', 'ignore it')) break if stone.stoneX > Game.barPosX - Game.stoneWidth and stone.stoneX < Game.barPosX + Game.barWidth: if stone.stoneY > Game.barPosY - Game.stoneHeight: # unsuccessful self.stateMessage = 'Missed...' thread.start_new_thread( self.playMusic, ('res\\Woosh-Mark_DiAngelo-4778593.wav', 'ignore it')) # # winsound.PlaySound('res\\Woosh-Mark_DiAngelo-4778593.wav', winsound.SND_FILENAME) break if stone.stoneX > opponent.playerX - Game.stoneWidth and stone.stoneX < opponent.playerX + Game.playerWidth: if stone.stoneY > opponent.playerY - Game.stoneHeight: # successful self.stateMessage = 'Hit!!' thread.start_new_thread( self.playMusic, ('res\\Realistic_Punch-Mark_DiAngelo-1609462330.wav', 'ignore it')) # winsound.PlaySound('res\\Realistic_Punch-Mark_DiAngelo-1609462330.wav', winsound.SND_FILENAME) # for not development purpose # player.score += 1 break self.paintField() QtTest.QTest.qWait(50) # ----------------------------- # # # # for development purpose # # # # ----------------------------- # # QtTest.QTest.qWait(1) # Till here # t += 0.3 if player1.score >= Game.gameScore: #player1 wins if Game.type == Game.Type.P2P: self.stateMessage = 'Player 1 wins <br> Press any key to continue' else: self.stateMessage = 'You Win..! <br> Press any key to continue' thread.start_new_thread( self.playMusic, ('res\\Applauding-and-cheering.mp3', 'ignore it')) Game.state = Game.GameState.GAMEOVER elif player2.score >= Game.gameScore: #player2 wins if Game.type == Game.Type.P2P: self.stateMessage = 'Player 2 wins <br> Press any key to continue' thread.start_new_thread( self.playMusic, ('res\\Applauding-and-cheering.mp3', 'ignore it')) else: self.stateMessage = 'You lose..! <br> Press any key to continue' thread.start_new_thread( self.playMusic, ('res\\fail-trombone-01.mp3', 'ignore it')) Game.state = Game.GameState.GAMEOVER else: if Game.turn == Game.Turn.P1: Game.turn = Game.Turn.P2 else: Game.turn = Game.Turn.P1 QTimer.singleShot(500, self.startToMove) # ----------------------------- # # # # for development purpose # # # # ----------------------------- # # QTimer.singleShot(1, self.startToMove) # Till here # def keyPressEvent(self, event): # print(event) if event.key() == Qt.Key_P and Game.state == Game.GameState.PLAY: Game.state = Game.GameState.PAUSED self.prevMessage = self.stateMessage self.stateMessage = 'Paused' self.paintField() elif Game.state == Game.GameState.PAUSED: if event.key() == Qt.Key_P: Game.state = Game.GameState.PLAY self.stateMessage = self.prevMessage self.paintField() elif event.key() == Qt.Key_Escape: QTimer.singleShot(50, self.homeUi) elif Game.state == Game.GameState.PLAY and Game.action != Game.Action.THROW: if Game.turn == Game.Turn.P1: if Game.type == Game.Type.P2P and Game.action == Game.Action.MOVE: if event.key() == Qt.Key_Left and Game.player2limitX[ 0] < player2.playerX: player2.move(-1) elif event.key( ) == Qt.Key_Right and player2.playerX < Game.player2limitX[ 1]: player2.move(1) elif Game.action == Game.Action.SET_ANGLE_FORCE: if event.key() == Qt.Key_W and angle_line.getAngle( ) < Game.player1AngleLimit[1]: angle_line.change(1) elif event.key() == Qt.Key_S and Game.player1AngleLimit[ 0] < angle_line.getAngle(): angle_line.change(-1) elif event.key( ) == Qt.Key_A and angle_line.getVel() > Game.minForceLen: angle_line.changeVel(-1) elif event.key( ) == Qt.Key_D and Game.maxForceLen > angle_line.getVel(): angle_line.changeVel(1) elif event.key() == Qt.Key_Space: Game.action = Game.Action.THROW self.throw() angle_line.current_vel = Game.defaultForceLen else: return else: if Game.action == Game.Action.MOVE: if event.key( ) == Qt.Key_A and Game.player1limitX[0] < player1.playerX: player1.move(-1) elif event.key( ) == Qt.Key_D and player1.playerX < Game.player1limitX[1]: player1.move(1) elif Game.action == Game.Action.SET_ANGLE_FORCE: if event.key() == Qt.Key_Down and angle_line.getAngle( ) < Game.player2AngleLimit[1]: angle_line.change(1) elif event.key() == Qt.Key_Up and Game.player2AngleLimit[ 0] < angle_line.getAngle(): angle_line.change(-1) elif event.key( ) == Qt.Key_Left and Game.maxForceLen > angle_line.getVel( ): angle_line.changeVel(1) elif event.key() == Qt.Key_Right and angle_line.getVel( ) > Game.minForceLen: angle_line.changeVel(-1) elif event.key() == Qt.Key_Space: Game.action = Game.Action.THROW self.throw() angle_line.current_vel = Game.defaultForceLen else: return self.paintField() elif Game.state == Game.GameState.GAMEOVER: QTimer.singleShot(50, self.homeUi) # print(self.position) def removeAllPaint(self): self.painter.fillRect(self.image.rect(), Qt.white) self.update() def paintField(self): self.removeAllPaint() self.painter.fillRect(0, Game.screenHeight - Game.fieldHeight, Game.screenWidth, Game.fieldHeight, Game.fieldColor) self.painter.fillRect(Game.barPosX, Game.barPosY, Game.barWidth, Game.barHeight, Game.fieldColor) self.painter.fillRect(player1.playerX, player1.playerY, Game.playerWidth, Game.playerHeight, Game.playerColor) self.painter.fillRect(player2.playerX, player2.playerY, Game.playerWidth, Game.playerHeight, Game.playerColor) self.painter.fillRect(stone.stoneX, stone.stoneY, Game.stoneWidth, Game.stoneWidth, Game.stoneColor) self.scoreText1 = '<b style="font-size:20px;">Player 1 : ' + str( player1.score) + '<\b>' if Game.type == Game.Type.P2P: self.scoreText2 = '<b style="font-size:20px;">Player 2 : ' + str( player2.score) + '<\b>' else: self.scoreText2 = '<b style="font-size:20px;">Computer : ' + str( player2.score) + '<\b>' self.message = '<b style="font-size:40px;">' + self.stateMessage + '<\b>' text1 = QtGui.QStaticText(self.scoreText1) text1.setTextFormat(Qt.RichText) text2 = QtGui.QStaticText(self.scoreText2) text2.setTextFormat(Qt.RichText) message = QtGui.QStaticText(self.message) message.setTextFormat(Qt.RichText) self.painter.drawStaticText(Game.scoreText1PosX, Game.scoreText1PosY, text1) self.painter.drawStaticText(Game.scoreText2PosX, Game.scoreText2PosY, text2) self.painter.drawStaticText(Game.stateMessageBoxX, Game.stateMessageBoxY, message) if Game.action == Game.Action.SET_ANGLE_FORCE: self.painter.drawLines(angle_line.getLines()) self.update() def paintEvent(self, event): canvas = QPainter(self) if Game.state == Game.GameState.PLAY or Game.state == Game.GameState.GAMEOVER: canvas.drawImage(self.rect(), self.image, self.image.rect()) elif Game.state == Game.GameState.PAUSED: message = '<b style="font-size:40px;">PAUSED<br> Press P to play or Esc to exit<\b>' message = QtGui.QStaticText(message) message.setTextFormat(Qt.RichText) canvas.drawStaticText(Game.stateMessageBoxX, Game.stateMessageBoxY, message) def playMusic(self, file, ignored): playsound(file) def closeEvent(self, event): # QCoreApplication.quit() # ----------------------------- # # # # for development purpose # # # # ----------------------------- # # numpy.save('modelDataReal.npy', Game.data) # Game.computer_vel.save('model6') # till here sys.exit()
def paintEvent(self, event): painter = QPainter() painter.begin(self) if not self.ignored: self.paint_background(painter) painter.setPen(QColor(255, 0, 255)) painter.setBrush(QColor(0, 0, 0)) for index, i in enumerate(self.initial_dots): painter.setPen(QColor(255, 0, 255)) painter.drawRect(i.x() - 1, i.y() - 1, 2, 2) try: end_point = self.final_dots[index] painter.setPen(QColor(0, 0, 255)) moving = False except IndexError: # There is no end point, so cursor is end point end_point = self.cursor().pos() painter.setPen(QColor(0, 0, 255, 64)) moving = True mid_point = QPoint(end_point.x(), i.y()) painter.drawPolyline(i, mid_point, end_point, i) painter.setPen(QColor(255, 0, 255)) halfx = (mid_point.x() - i.x()) / 2 + i.x() halfy = (end_point.y() - mid_point.y()) / 2 + mid_point.y() # Draw perpendicular magenta lines in each of the triangle's sides' center top_horizontal_half = QPoint(halfx, i.y() + 10) bot_horizontal_half = QPoint(halfx, i.y() - 10) left_vertical_half = QPoint(end_point.x() - 10, halfy) right_vertical_half = QPoint(end_point.x() + 10, halfy) try: hipotenuse = math.sqrt((2 * (halfx - i.x()))**2 + (2 * (halfy - mid_point.y()))**2) scaling_factor = hipotenuse / 10 # To ensure line length = 10 y_change = (2 * (halfx - i.x()) / scaling_factor) x_change = (2 * (halfy - mid_point.y()) / scaling_factor) except ZeroDivisionError: y_change = 0 x_change = 0 top_hipotenuse_half = QPoint(halfx - x_change, halfy + y_change) bot_hipotenuse_half = QPoint(halfx + x_change, halfy - y_change) if hipotenuse >= 20 and moving: # To not be in the way while looking for a second point painter.drawLine(top_horizontal_half, bot_horizontal_half) painter.drawLine(left_vertical_half, right_vertical_half) painter.drawLine(top_hipotenuse_half, bot_hipotenuse_half) painter.setPen(QColor(255, 255, 255)) x_px = abs(int((halfx - i.x()) * 2)) + 1 y_px = abs(int((halfy - mid_point.y()) * 2)) + 1 hipotenuse = abs(hipotenuse) inch_to_cm = 2.54 x_inches = x_px / self.ppix y_inches = y_px / self.ppiy hip_inches = hipotenuse / ((self.ppiy + self.ppix) / 2) x_cm = x_inches * inch_to_cm y_cm = y_inches * inch_to_cm hip_cm = hip_inches * inch_to_cm x_text = str( x_px ) + "px | " + f"{x_cm:7.2f}" + "cm | " + f"{x_inches:7.2f}" + "inch" y_text = str( y_px ) + "px | " + f"{y_cm:7.2f}" + "cm | " + f"{y_inches:7.2f}" + "inch" hip_text = f"{abs(hipotenuse):7.2f}" + "px | " + f"{hip_cm:7.2f}" + "cm | " + f"{hip_inches:7.2f}" + "inch" # in 7.2f -> 7 = max char, 2 = max floating point precision if moving and hipotenuse >= 20: # To not be in the way while looking for a second point painter.drawText(QPoint(halfx, i.y()), x_text) painter.drawText(QPoint(end_point.x(), halfy), y_text) painter.drawText( QPoint(halfx, halfy - 12), hip_text) # 7 = max char, 2 = max floating point precision elif not moving: # drawStaticText is more optimized if it rarely updates painter.drawStaticText(QPoint(halfx, i.y()), QStaticText(x_text)) painter.drawStaticText(QPoint(end_point.x(), halfy), QStaticText(y_text)) painter.drawStaticText(QPoint(halfx, halfy - 12), QStaticText(hip_text)) painter.setPen(QColor(255, 0, 255)) for i in self.final_dots: painter.drawRect(i.x() - 1, i.y() - 1, 2, 2) """if not self.ignored: self.paint_cursor(painter)""" painter.end()
class PixelWidget(QWidget): def __init__(self, form, bufhandler): super(PixelWidget, self).__init__() self.form = form self.set_zoom(10) self.maxPixelsPerLine = 64 self.maxPixelsTotal = 0 self.prev_mouse_y = 0 self.key = None self.buffers = None self.offs = 0 self.base = 0 self.fm = None self.filter_idx = 0 self.mouseOffs = 0 self.sync = True self.bh = bufhandler self.mouse_abs_x = 0 self.mouse_abs_y = 0 self.elemX = 0 self.elemY = 0 self.rect_x = 0 self.rect_x_width = 0 self.lock_width = False self.lock_sync = False self.link_pixel = True self.highlight_cursor = False self.render_data = True self.cur_formatter_idx = 0 self.max_formatters = 2 self.setMouseTracking(True) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.sh = SignalHandler() self.statechanged = self.sh.pw_statechanged self.next_filter = self.sh.pw_next_filter self.prev_filter = self.sh.pw_prev_filter self.qp = QPainter() self.show() def paintEvent(self, event): if not self.fm: return # set leftmost x-coordinate of graph zoom_level = self.get_zoom() self.rect_x_width = self.get_width() * zoom_level self.rect_x = (self.rect().width() / 2) - (self.rect_x_width / 2) self.qp.begin(self) # what is a good default font for OSX/Linux? self.qp.setFont(QFont(FONT_DEFAULT)) # fill background self.qp.fillRect(self.rect(), Qt.black) content_addr = content_size = None if self.fm.support_selection: selected, start, end = ida_kernwin.read_range_selection(None) if selected: content_addr = start #min(start, end) content_size = end - start #max(start, end) - content_addr # use colorfilter to render image img = self.render_image(addr=content_addr, buf_size=content_size) if img: """ if zoom_level > 6: opacity = self.qp.opacity() full_opacity_zoom = 40.0 cur_opacity = (1.0 - (full_opacity_zoom - float(min(zoom_level-1, full_opacity_zoom)))/full_opacity_zoom) self.qp.setOpacity(1.0-cur_opacity) """ # draw image self.qp.drawImage( QRect( QPoint(self.rect_x, 0), QPoint(self.rect_x + self.get_width() * zoom_level, (self.get_pixels_total() / self.get_width()) * zoom_level)), img) # TODO: pen color contrast # TODO: data export: render data # TODO: default fonts / OS? # TODO: optimization # FIXME: there's a bug with gaps/unmapped buffers if self.render_data and not self.fm.disable_data and zoom_level > 6: self.qp.setPen(QColor(Qt.white)) fontsize = self.qp.font().pointSize() font = self.qp.font() font.setPointSize(zoom_level / 3) self.qp.setFont(font) opacity = self.qp.opacity() full_opacity_zoom = 28 cur_opacity = ( 1.0 - (full_opacity_zoom - float(min(zoom_level - 1, full_opacity_zoom))) / full_opacity_zoom) self.qp.setOpacity(cur_opacity) m = self.qp.fontMetrics() x = y = 0 num_pixels_per_row = self.get_width() if self.cur_formatter_idx == 0: sample = "%c" % (ord('X')) cwidth = m.width(sample) cheight = m.height() for mapped, buf in self.buffers: for i in range(len(buf)): if mapped: b = ord(buf[i]) data = "%c" % (chr(b) if b in range( 0x20, 0x7E) else ".") self.qp.drawStaticText( self.rect_x + x * zoom_level + (zoom_level - cwidth) / 2, y * zoom_level + (zoom_level - cheight) / 2, QStaticText(data)) x = (i + 1) % num_pixels_per_row if not x: y = y + 1 elif self.cur_formatter_idx == 1: sample = "%02X" % (ord('X')) cwidth = m.width(sample) cheight = m.height() for mapped, buf in self.buffers: for i in range(len(buf)): if mapped: data = "%02X" % ord(buf[i]) self.qp.drawStaticText( self.rect_x + x * zoom_level + (zoom_level - cwidth) / 2, y * zoom_level + (zoom_level - cheight) / 2, QStaticText(data)) x = (i + 1) % num_pixels_per_row if not x: y = y + 1 self.qp.setOpacity(opacity) font.setPointSize(fontsize) self.qp.setFont(font) if self.show_address_range and self.fm.link_pixel: self.render_slider(addr=content_addr, buf_size=content_size) # get and draw annotations and pointers annotations = self.fm.on_get_annotations( content_addr if content_addr else self.get_address(), self.get_pixels_total(), self.mouseOffs) if annotations: self.render_annotations(annotations) self.qp.end() return def render_slider(self, addr=None, buf_size=None): if addr is None or buf_size is None: addr = self.base + self.offs buf_size = self.get_pixels_total() lowest_ea = ida_idaapi.get_inf_structure().get_minEA() highest_ea = ida_idaapi.get_inf_structure().get_maxEA() start_offs = addr - lowest_ea addr_space = highest_ea - lowest_ea perc_s = float(start_offs) / float(addr_space) perc_e = float(start_offs + buf_size) / float(addr_space) bar_width = 20 spaces_bar = 5 bar_x = self.rect_x - spaces_bar - bar_width bar_y = 5 bar_height = self.rect().height() - 2 * bar_y self.qp.fillRect(bar_x, bar_y, bar_width, bar_height, QColor(0x191919)) slider_offs_s = int(round(perc_s * bar_height)) slider_offs_e = int(round(perc_e * bar_height)) spaces_slider = 1 slider_x = bar_x + spaces_slider slider_y = bar_y + slider_offs_s slider_width = bar_width - 2 * spaces_slider # limit slider height to bar_height slider_height = max( min(slider_offs_e - slider_offs_s, bar_height - (slider_y - bar_y)), 4) self.qp.fillRect(slider_x, slider_y, slider_width, slider_height, QColor(0x404040)) # draw addresses top = '%X:' % self.get_address() bottom = '%X' % (self.get_address() + ((self.get_pixels_total() / self.get_width()) - 1) * self.get_width()) self.qp.setPen(QColor(0x808080)) self.qp.drawText( self.rect_x - self.qp.fontMetrics().width(top) - bar_width - 2 * spaces_bar, self.qp.fontMetrics().height(), top) self.qp.drawText( self.rect_x - self.qp.fontMetrics().width(bottom) - bar_width - 2 * spaces_bar, self.rect().height() - self.qp.fontMetrics().height() / 2, bottom) return def render_image(self, addr=None, buf_size=None, cursor=True): size = self.size() self.maxPixelsTotal = self.get_width() * (size.height() / self.pixelSize) if addr is None or buf_size is None: addr = self.base + self.offs buf_size = self.get_pixels_total() self.buffers = self.bh.get_buffers(addr, buf_size) img = QImage(self.get_width(), size.height() / self.pixelSize, QImage.Format_RGB32) pixels = self.fm.on_process_buffer(self.buffers, addr, self.get_pixels_total(), self.mouseOffs) x = y = 0 # transparency effect for unmapped bytes transparency_dark = [qRgb(0x2F, 0x4F, 0x4F), qRgb(0x00, 0x00, 0x00)] transparency_err = [qRgb(0x7F, 0x00, 0x00), qRgb(0x33, 0x00, 0x00)] for mapped, pix in pixels: if not mapped: if pix is None: pix = transparency_dark[(x & 2 != 0) ^ (y & 2 != 0)] img.setPixel(x, y, pix) x = (x + 1) % self.get_width() if not x: y = y + 1 if len(pixels) != self.get_pixels_total(): for i in xrange(self.get_pixels_total() - len(pixels)): pix = transparency_err[(x & 2 != 0) ^ (y & 2 != 0)] img.setPixel(x, y, pix) x = (x + 1) % self.get_width() if not x: y = y + 1 if ((cursor and self.fm.highlight_cursor) and self.mouse_abs_x >= self.rect_x and self.mouse_abs_x < self.rect_x + self.rect_x_width): coords = self.get_coords_by_address(self.get_cursor_address()) if coords: x, y = coords else: x = self.get_elem_x() y = self.get_elem_y() p = QPoint(x, y) img.setPixel(p, ~(img.pixelColor(p)).rgb()) return img def render_annotations(self, annotations=[]): a_offs = 20 base_x = self.rect_x + self.get_width() * self.pixelSize + a_offs + 10 base_y = self.qp.fontMetrics().height() offs_x = 5 offs_y = base_y for coords, arr_color, ann, txt_color in annotations: # draw arrow (experimental / WIP) self.qp.setPen( QColor(Qt.white if txt_color is None else txt_color)) self.qp.drawText(base_x + 10, (base_y + offs_y) / 2, ann) target_x = target_y = None if coords: if isinstance(coords, tuple): target_x, target_y = coords else: ptr = self.get_coords_by_address(coords) if ptr: target_x, target_y = ptr if target_x is not None and target_y is not None: target_x *= self.get_zoom() target_y *= self.get_zoom() self.qp.setPen( QColor(Qt.white if arr_color is None else arr_color)) path = QPainterPath() path.moveTo(base_x + offs_x, (base_y + offs_y) / 2 - base_y / 2) path.lineTo(base_x + offs_x - 4 - a_offs, (base_y + offs_y) / 2 - base_y / 2) # left path.lineTo(base_x + offs_x - 4 - a_offs, ((target_y / 10) * 9) + self.get_zoom() / 2) # down path.lineTo(self.rect_x + target_x + self.get_zoom() / 2, ((target_y / 10) * 9) + self.get_zoom() / 2) # left path.lineTo(self.rect_x + target_x + self.get_zoom() / 2, target_y + self.get_zoom() / 2) # down a_offs = max(a_offs - 2, 0) self.qp.drawPath(path) else: if not isinstance(coords, tuple): direction = self.get_target_direction(coords) if direction: self.qp.setPen( QColor(Qt.white if arr_color is None else arr_color)) m = self.qp.fontMetrics() dirhint = ['', '<<', '>>'][direction] cwidth = m.width("%s" % (dirhint)) self.qp.drawText(base_x - cwidth, (base_y + offs_y) / 2, dirhint) offs_y += 2 * base_y + 5 return # functions that can be called by filters # must no be called from within on_process_buffer() def on_filter_request_update(self, ea=None, center=True): if not ea: self.repaint() else: curea = self.get_address() if ea < curea or ea >= curea + self.get_pixels_total(): # TODO: verify that ea is valid after following operation if center: ea -= self.get_pixels_total() / 2 self.set_addr(ea) else: self.repaint() def on_filter_update_zoom(self, zoom): self.set_zoom(zoom) return def on_filter_update_zoom_delta(self, delta): self.set_zoom_delta(delta) return # end of functions that can be called by filters def show_help(self): ida_kernwin.info("%s" % PLUGIN_HELP) def keyPressEvent(self, event): if self.key is None: self.key = event.key() return def keyReleaseEvent(self, event): update = False key = event.key() modifiers = event.modifiers() shift_pressed = ((modifiers & Qt.ShiftModifier) == Qt.ShiftModifier) ctrl_pressed = ((modifiers & Qt.ControlModifier) == Qt.ControlModifier) if key == Qt.Key_F1 and ctrl_pressed: self.show_help() elif key == Qt.Key_G: addr = ask_addr(self.base + self.offs, 'Jump to address') if addr is not None: if self.sync: ida_kernwin.jumpto(addr) else: minea = ida_idaapi.get_inf_structure().get_minEA() maxea = ida_idaapi.get_inf_structure().get_maxEA() dst = min(max(addr, minea), maxea) self.set_addr(dst) elif key == Qt.Key_S: if not self.fm.lock_sync: self.set_sync_state(not self.get_sync_state()) update = True elif key == Qt.Key_T: self.render_data = not self.render_data self.repaint() elif key == Qt.Key_D: self.cur_formatter_idx = (self.cur_formatter_idx + 1) % self.max_formatters self.repaint() elif key == Qt.Key_N: self.next_filter.emit() elif key == Qt.Key_B: self.prev_filter.emit() elif key == Qt.Key_F2: hlp = self.fm.help if hlp is None: hlp = 'Help unavailable' ida_kernwin.info('%s\n\n' % hlp) elif key == Qt.Key_F12: img = self.render_image(cursor=False) img = img.scaled(img.width() * self.pixelSize, img.height() * self.pixelSize, Qt.KeepAspectRatio, Qt.FastTransformation) done = False i = 0 while not done: fname = 'IDACyber_%04d.bmp' % i if not os.path.isfile(fname): if img.save(fname): ida_kernwin.msg('File exported to %s\n' % fname) else: ida_kernwin.warning( 'Error exporting screenshot to %s.' % fname) done = True i += 1 if i > 40: ida_kernwin.warning('Aborted. Error exporting screenshot.') break elif key == Qt.Key_PageDown: self.set_offset_delta(-self.get_pixels_total()) update = True elif key == Qt.Key_PageUp: self.set_offset_delta(self.get_pixels_total()) update = True elif key == Qt.Key_Down: if shift_pressed: self.set_offset_delta(-1) else: self.set_offset_delta(-self.get_width()) update = True elif key == Qt.Key_Up: if shift_pressed: self.set_offset_delta(1) else: self.set_offset_delta(self.get_width()) update = True elif key == Qt.Key_Plus: if ctrl_pressed: self.set_zoom_delta(1) update = True elif key == Qt.Key_Minus: if ctrl_pressed: self.set_zoom_delta(-1) update = True self.key = None if update: if self.get_sync_state(): ida_kernwin.jumpto(self.base + self.offs) self.activateWindow() self.setFocus() self.statechanged.emit() self.repaint() return def mouseReleaseEvent(self, event): self.prev_mouse_y = event.pos().y() self.fm.on_mb_click(event, self.get_address(), self.get_pixels_total(), self.mouseOffs) if self.get_sync_state(): ida_kernwin.jumpto(self.base + self.offs) self.activateWindow() self.setFocus() self.statechanged.emit() return def mouseDoubleClickEvent(self, event): if self.link_pixel and event.button() == Qt.LeftButton: addr = self.base + self.offs + self._get_offs_by_pos(event.pos()) ida_kernwin.jumpto(addr) return def wheelEvent(self, event): delta = event.angleDelta().y() / 120 # zoom if self.key == Qt.Key_Control: self.set_zoom_delta(delta) # width elif self.key == Qt.Key_X: if not self.lock_width: self.set_width_delta(delta) # offset (fine) elif self.key == Qt.Key_Shift: self.set_offset_delta(delta) if self.get_sync_state(): ida_kernwin.jumpto(self.base + self.offs) self.activateWindow() self.setFocus() elif self.key == Qt.Key_H: if not self.lock_width: less = delta < 0 w = -8 if less else 8 self.set_width((self.get_width() & 0xFFFFFFF8) + w) # offset (coarse) else: self.set_offset_delta(delta * self.get_width()) if self.get_sync_state(): ida_kernwin.jumpto(self.base + self.offs) self.activateWindow() self.setFocus() self.statechanged.emit() self.repaint() return def mouseMoveEvent(self, event): x = event.pos().x() y = event.pos().y() within_graph = (x >= self.rect_x and x < self.rect_x + self.rect_x_width) if within_graph: if event.buttons() == Qt.NoButton: self._update_mouse_coords(event.pos()) self.mouseOffs = self._get_offs_by_pos(event.pos()) if self.link_pixel and self.highlight_cursor: highlight_item( ida_bytes.get_item_head(self.get_cursor_address())) elif self.highlight_cursor: unhighlight_item() self.setToolTip( self.fm.on_get_tooltip(self.get_address(), self.get_pixels_total(), self.mouseOffs)) # zoom elif self.key == Qt.Key_Control: self.set_zoom_delta(-1 if y > self.prev_mouse_y else 1) # width elif self.key == Qt.Key_X: if not self.lock_width: self.set_width_delta(-1 if y > self.prev_mouse_y else 1) elif self.key == Qt.Key_H: if not self.lock_width: less = y > self.prev_mouse_y delta = -16 if less else 16 self.set_width((self.get_width() & 0xFFFFFFF0) + delta) # scrolling (offset) elif y != self.prev_mouse_y: # offset (fine) delta = y - self.prev_mouse_y # offset (coarse) if self.key != Qt.Key_Shift: delta *= self.get_width() self.set_offset_delta(delta) self.prev_mouse_y = y self.x = x self.statechanged.emit() self.repaint() return def set_sync_state(self, sync): self.sync = sync def get_sync_state(self): return self.sync def get_filter_idx(self): return self.filter_idx def set_filter(self, fltobj, idx): if self.fm: self.fm.on_deactivate() if fltobj: self.fm = fltobj """load filter config""" self.set_sync_state(self.fm.sync) self.lock_width = self.fm.lock_width self.set_width(self.fm.width) self.lock_sync = self.fm.lock_sync self.show_address_range = self.fm.show_address_range # disabled for now # self.set_zoom(self.fm.zoom) self.link_pixel = self.fm.link_pixel self.highlight_cursor = self.fm.highlight_cursor self.statechanged.emit() """load filter config end""" self.fm.on_activate(idx) self.filter_idx = idx unhighlight_item() self.repaint() def set_addr(self, ea, new_cursor=None): base = self.bh.get_base(ea) self._set_base(base) self._set_offs(ea - base) if new_cursor: self.set_cursor_address(new_cursor) if self.highlight_cursor: highlight_item(ea) self.repaint() def get_zoom(self): return self.pixelSize def set_zoom(self, zoom): self.pixelSize = zoom def set_zoom_delta(self, dzoom): self.set_zoom(max(1, self.pixelSize + dzoom)) return def get_width(self): return self.maxPixelsPerLine def get_pixels_total(self): return self.maxPixelsTotal def get_address(self): return self.base + self.offs def get_cursor_address(self): return self.get_address() + self.mouseOffs def set_cursor_address(self, ea): self.mouseOffs = ea - self.get_address() def get_coords_by_address(self, address): base = self.get_address() # if address is visible in current window if address >= base and address < base + self.get_pixels_total(): offs = address - base x = offs % self.get_width() y = offs / (self.get_width()) return (x, y) return None def get_target_direction(self, address): base = self.get_address() # if address is visible in current window direction = None if address >= base and address < base + self.get_pixels_total(): direction = 0 elif address < base: direction = 1 else: direction = 2 return direction def set_width(self, width): self.maxPixelsPerLine = max(1, width) def set_width_delta(self, dwidth): self.maxPixelsPerLine = max(1, self.maxPixelsPerLine + dwidth) def set_offset_delta(self, doffs): newea = self.base + self.offs - doffs minea = ida_idaapi.get_inf_structure().get_minEA() maxea = ida_idaapi.get_inf_structure().get_maxEA() if doffs < 0: delta = doffs if newea < maxea else doffs - (maxea - newea) else: delta = doffs if newea >= minea else doffs - (minea - newea) self._set_offs(self.offs - delta) def _get_offs_by_pos(self, pos): elemX = self.get_elem_x() elemY = self.get_elem_y() offs = elemY * self.get_width() + elemX return offs def _update_mouse_coords(self, pos): x = pos.x() y = pos.y() self.mouse_abs_x = x self.mouse_abs_y = y self.elemX = max( 0, min((max(0, x - self.rect_x)) / self.pixelSize, self.get_width() - 1)) self.elemY = min(y / self.pixelSize, self.maxPixelsTotal / self.get_width() - 1) def get_elem_x(self): return self.elemX def get_elem_y(self): return self.elemY def _set_offs(self, offs): self.offs = offs def _set_base(self, ea): self.base = ea
def on_frame_ready(self, frame: QImage, info, instances): self.process_results(instances) video = self.ui.video table = self.ui.infoTable origin_pixmap = QPixmap.fromImage(frame) painter = QPainter() pixmap = origin_pixmap.scaled(video.width(), video.height(), Qt.KeepAspectRatio) painter.begin(pixmap) width_scale = pixmap.width() / origin_pixmap.width() height_scale = pixmap.height() / origin_pixmap.height() def translate_bbox(bbox): return [ width_scale * bbox[0], height_scale * bbox[1], width_scale * bbox[2], height_scale * bbox[3] ] font = painter.font() font.setPointSize(FONT_SIZE) painter.setFont(font) for instance in instances: color = instance['instance_color'] painter.setPen(QPen(QColor(color), 4)) bbox = translate_bbox(instance['instance_bbox']) painter.drawRect(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]) if instance['face'] is not None: painter.setPen(QPen(QColor(instance['face_color']), 2)) bbox = translate_bbox(instance['face_bbox']) painter.drawRect(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]) for instance in instances: bbox = translate_bbox(instance['instance_bbox']) attributes = { **instance['attributes'], 'ID': instance['instance_name'] or str(instance['instance'])[:8], } height = len(attributes) * (FONT_SIZE + FONT_SPACE) + 2 * FONT_SPACE top = bbox[1] - height if instance['blacklist'] is not None: background_color = QColor(0xff0000) else: background_color = QColor(0xffffff) background_color.setAlphaF(0.5) painter.fillRect(bbox[0], top, 150, height, background_color) painter.setPen(QPen(QColor(0x0))) top += FONT_SPACE for key, value in attributes.items(): painter.drawStaticText(bbox[0] + FONT_SPACE, top, QStaticText('%s: %s' % (key, value))) top += FONT_SIZE + FONT_SPACE for instance in instances: if instance['face'] is None: continue bbox = translate_bbox(instance['face_bbox']) attributes = { 'ID': instance['face_name'] or str(instance['face'])[:8], } if instance['blacklist'] is not None: attributes['黑名单'] = instance['blacklist_name'] or str( instance['blacklist'])[:8] background_color = QColor(0xff0000) else: background_color = QColor(0xffffff) height = len(attributes) * (FONT_SIZE + FONT_SPACE) + 2 * FONT_SPACE top = bbox[3] background_color.setAlphaF(0.5) painter.fillRect(bbox[0], top, 100, height, background_color) painter.setPen(QPen(QColor(0x0))) top += FONT_SPACE for key, value in attributes.items(): painter.drawStaticText(bbox[0] + FONT_SPACE, top, QStaticText('%s: %s' % (key, value))) top += FONT_SIZE + FONT_SPACE painter.end() video.setPixmap(pixmap) table.item(VideoInfoRow.Frame, 1).setText(str(info[VideoInfoRow.Frame])) table.item(VideoInfoRow.Time, 1).setText('%.2f' % info[VideoInfoRow.Time]) table.item(VideoInfoRow.Progress, 1).setText('%.2f' % (info[VideoInfoRow.Progress] * 100)) time = math.floor(info[VideoInfoRow.Time] / 1000) if self.ui.playSlider.isEnabled(): self.ui.playSlider.blockSignals(True) self.ui.playSlider.setValue(info[VideoInfoRow.Frame] - 1) self.ui.playSlider.blockSignals(False) self.ui.progressText.setText( '%02d:%02d/%s %d/%d' % (time // 60, time % 60, self.total_time_text, info[VideoInfoRow.Frame], self.total_frames))