def __init__(self, parent, uid): QtGui.QLabel.__init__(self, parent) BackendQuadrant.__init__(self, uid) self.prnt = parent self.setMouseTracking(True) self.bg_image = QtGui.QImage( pypentago.data['quad_bg.png'] ) # 0 1 | With 0 aligned properly, # 2 3 | 1 and 3 need to be mirrored horizontally, 2 and 3 verticaly. # While horizontally mirror means "| *" -> "* |", meaning that the # mirror axis lies vertically. self.bg_image = self.bg_image.mirrored(uid == 1 or uid == 3, uid == 2 or uid == 3) # Clockwise rotation image overlay. self.rot_cw = SVGFakePixmap( pypentago.data['rot_cw.svg'] ) # Counter-clockwise rotation image overlay. self.rot_ccw = SVGFakePixmap( pypentago.data['rot_ccw.svg'] ) self.img = [ QtGui.QImage( pypentago.data['ball-empty.png'] ), QtGui.QImage( pypentago.data['ball-white.png'] ), QtGui.QImage( pypentago.data['ball-black.png'] ), ] self.stone_background = QtGui.QImage( pypentago.data['ball-bg.png'] ) self.overlay = Overlay(self.repaint) self.blink_timer = QtCore.QTimer(self) self.preview_stone = None self.blink_cw = OverlayBlink(self.overlay, self.repaint) self.blink_ccw = OverlayBlink(self.overlay, self.repaint) self.blink_stone = StoneBlink(self.repaint) self.block_user_control = [self.blink_ccw, self.blink_cw, self.blink_stone]
class Quadrant(QtGui.QLabel, BackendQuadrant): PREVIEW_OPACITY = 0.4 def __init__(self, parent, uid): QtGui.QLabel.__init__(self, parent) BackendQuadrant.__init__(self, uid) self.prnt = parent self.setMouseTracking(True) self.bg_image = QtGui.QImage( pypentago.data['quad_bg.png'] ) # 0 1 | With 0 aligned properly, # 2 3 | 1 and 3 need to be mirrored horizontally, 2 and 3 verticaly. # While horizontally mirror means "| *" -> "* |", meaning that the # mirror axis lies vertically. self.bg_image = self.bg_image.mirrored(uid == 1 or uid == 3, uid == 2 or uid == 3) # Clockwise rotation image overlay. self.rot_cw = SVGFakePixmap( pypentago.data['rot_cw.svg'] ) # Counter-clockwise rotation image overlay. self.rot_ccw = SVGFakePixmap( pypentago.data['rot_ccw.svg'] ) self.img = [ QtGui.QImage( pypentago.data['ball-empty.png'] ), QtGui.QImage( pypentago.data['ball-white.png'] ), QtGui.QImage( pypentago.data['ball-black.png'] ), ] self.stone_background = QtGui.QImage( pypentago.data['ball-bg.png'] ) self.overlay = Overlay(self.repaint) self.blink_timer = QtCore.QTimer(self) self.preview_stone = None self.blink_cw = OverlayBlink(self.overlay, self.repaint) self.blink_ccw = OverlayBlink(self.overlay, self.repaint) self.blink_stone = StoneBlink(self.repaint) self.block_user_control = [self.blink_ccw, self.blink_cw, self.blink_stone] def paintEvent(self, event): # We might want to change that for performance reasons later on. # Either FastTransformation or SmoothTransformation. s_mode = QtCore.Qt.SmoothTransformation h = self.height() w = self.width() min_size = min([h, w]) paint = QtGui.QPainter() paint.begin(self) # Resize the background image. bg = self.bg_image.scaledToHeight(min_size, s_mode) paint.drawImage(0, 0, bg) s_size = min_size - min_size / 6.0 # The space a stone has got is a third of the total space # available. size = s_size / 3.0 # The size of one stone is a fourth of either the height or the # width of the quadrant, depending which of them is smaller. w_size = size / 1.25 # What we need to add to compensate for the difference of the img # and the total size. d_size = (size - w_size) / 2.0 + (min_size - s_size) / 2.0 # Scale all of the images to one fourth of the space we've got. # We're assuming to work with squared images! imgs = [img.scaledToHeight(w_size, s_mode) for img in self.img] if self.blink_stone: b_col, b_row = self.blink_stone.coord else: b_col, b_row = None, None for y_c, row in enumerate(self.field): y_p = y_c * size for x_c, col in enumerate(row): x_p = x_c * size if x_c == b_col and y_c == b_row: paint.setOpacity(self.blink_stone.value) stone_value = self.field[y_c][x_c] paint.drawImage(x_p+d_size, y_p+d_size, self.stone_background) paint.drawImage(x_p+d_size, y_p+d_size, imgs[stone_value]) if x_c == b_col and y_c == b_row: paint.setOpacity(1) if self.preview_stone is not None: x_c, y_c = self.preview_stone if 0 <= x_c <= 2 and 0 <= y_c <= 2 and not self.field[y_c][x_c]: uid = self.prnt.prnt.local_player.uid x_p, y_p = x_c * size, y_c * size paint.setOpacity(self.PREVIEW_OPACITY) paint.drawImage(x_p+d_size, y_p+d_size, imgs[uid]) paint.setOpacity(1) if self.overlay: # Display rotation overlay. rot_cw = self.rot_cw.scaledToWidth(w / 2.0, s_mode) rot_ccw = self.rot_ccw.scaledToWidth(w / 2.0, s_mode) cw_y = h / 2.0 - rot_cw.height() / 2.0 ccw_y = h / 2.0 - rot_ccw.height() / 2.0 cw_o, ccw_o = self.overlay.opacity paint.setOpacity(cw_o + self.blink_cw.value) paint.drawPixmap(0, cw_y, rot_cw) if ccw_o != cw_o or self.blink_ccw or self.blink_cw: paint.setOpacity(ccw_o + self.blink_ccw.value) paint.drawPixmap(w / 2.0, ccw_y, rot_ccw) paint.setOpacity(1) # This was a triumph! paint.end() def rotate(self, clockwise, user_done=True): BackendQuadrant.rotate(self, clockwise) self.prnt.may_rot = False self.overlay.hide() self.repaint() if user_done: self.prnt.do_turn(clockwise and "CW" or "CCW", self.uid) def show_rot(self, clockwise, callafter=None): if clockwise: self.blink_cw.run(5000, callafter) else: self.blink_ccw.run(5000, callafter) def show_loc(self, col, row, callafter=None): self.blink_stone.coord = (col, row) self.blink_stone.run(5000, callafter) def mousePressEvent(self, event): if not self.prnt.user_control: self.prnt.reclaim_control() return if self.prnt.may_rot and not self.overlay: # This shouldn't actually be happening. Just in case it is. warnings.warn('may_rot == True and mousePressEvent but no overlay') return x, y = event.x(), event.y() w = self.width() h = self.height() if self.overlay: if x < w / 2.0: # Clockwise self.rotate(True) else: # Counter-clockwise self.rotate(False) self.repaint() # Update outdated position of preview stone. self.mouseMoveEvent(event) else: # No overlay. Player wants to set a stone. size = min([h, w]) / 3.0 x, y = get_coord(size, x), get_coord(size, y) self.set_stone(y, x) def enterEvent(self, event): if self.prnt.may_rot: self.overlay.show() self.repaint() def leaveEvent(self, event): if not (self.blink_ccw or self.blink_cw): self.overlay.hide() self.preview_stone = None self.repaint() def mouseMoveEvent(self, event): if not self.prnt.user_control: return if not self.overlay: x, y = event.x(), event.y() size = min([self.height(), self.width()]) / 3.0 x, y = get_coord(size, x), get_coord(size, y) if x > 3 or x < 0 or y > 3 or y < 0: warnings.warn("Attempting out-of-range preview stone at " "row %r and col %r" % (y, x)) self.preview_stone = None else: self.preview_stone = x, y self.repaint() return else: x = event.x() if x < self.width() / 2.0: self.overlay.highlight_cw() else: self.overlay.highlight_ccw() self.repaint() def set_stone(self, row, col, player_id=None, may_rot=True): if player_id is None: player_id = self.prnt.prnt.local_player.uid if self.field[row][col]: return self.field[row][col] = player_id self.prnt.may_rot = may_rot self.prnt.temp_turn = [self.uid, row, col] if may_rot: self.overlay.show() self.repaint() @property def user_control(self): return not any(self.block_user_control) def reclaim_control(self): for elem in self.block_user_control: if elem: elem.stop()