def maskedIcon(qcolor, maskImg: QtGui.QPixmap): """ Creates an icon of a given color from the given mask """ img = QtGui.QPixmap(maskImg.size()) mask = maskImg.createMaskFromColor( QtGui.QColor("black"), QtCore.Qt.MaskOutColor ) img.fill(qcolor) img.setMask(mask) return img
def update_eraser_pixle_size(self, pixle_size): self.eraser_pixle_size = pixle_size eraser_cursor_pix = QPixmap( QSize(self.eraser_pixle_size, self.eraser_pixle_size)) eraser_cursor_pix.fill(QColor(255, 255, 255)) eraser_cursor_pix_painter = QPainter(eraser_cursor_pix) eraser_cursor_pix_painter.setBrush(self.eraser_color) eraser_cursor_pix_painter.drawEllipse( QRect(QPoint(-2, -2), QPoint(self.eraser_pixle_size, self.eraser_pixle_size))) eraser_cursor_pix_painter.end() eraser_cursor_pix.setMask( eraser_cursor_pix.createMaskFromColor(self.eraser_color, Qt.MaskOutColor)) self.eraser_model_cursor = QCursor(eraser_cursor_pix) if self.eraser_painting_model: self.setCursor(self.eraser_model_cursor)
def update_brush_pixle_size(self, pixle_size): self.brush_pixle_size = pixle_size brush_cursor_pix = QPixmap( QSize(self.brush_pixle_size, self.brush_pixle_size)) brush_cursor_pix.fill(QColor(0, 0, 0)) brush_cursor_pix_painter = QPainter(brush_cursor_pix) brush_cursor_pix_painter.setBrush(self.brush_color) brush_cursor_pix_painter.drawEllipse( QRect(QPoint(-2, -2), QPoint(self.brush_pixle_size, self.brush_pixle_size))) brush_cursor_pix_painter.end() brush_cursor_pix.setMask( brush_cursor_pix.createMaskFromColor(self.brush_color, Qt.MaskOutColor)) self.brush_model_cursor = QCursor(brush_cursor_pix) if not self.eraser_painting_model: self.setCursor(self.brush_model_cursor)
class ShipPainter(BasePainter): def __init__(self, parent): BasePainter.__init__(self, parent) def setup(self): if self.is_set: return # Load ship bitmap self._ship_alive = QPixmap(IMAGE_SHIP_PATH) self._ship_alive.setMask( self._ship_alive.createMaskFromColor(QColor(0, 0, 0))) self._ship_dead = self._ship_alive.copy() _comon_color = QPixmap(self._ship_alive.size()) _comon_color.fill(QColor(0, 255, 0)) _comon_color.setMask( self._ship_alive.createMaskFromColor(QColor(255, 255, 255), mode=Qt.MaskOutColor)) _dead_color = QPixmap(self._ship_dead.size()) _dead_color.fill(QColor(100, 100, 100)) _dead_color.setMask( self._ship_dead.createMaskFromColor(QColor(255, 255, 255), mode=Qt.MaskOutColor)) painter = QPainter(self._ship_alive) painter.setRenderHint(QPainter.Antialiasing) painter.drawPixmap(QPoint(0, 0), _comon_color) painter.end() painter = QPainter(self._ship_dead) painter.setRenderHint(QPainter.Antialiasing) painter.drawPixmap(QPoint(0, 0), _dead_color) painter.end() self._ship_alive = self._ship_alive.scaledToHeight( 50, mode=Qt.SmoothTransformation) self._ship_dead = self._ship_dead.scaledToHeight( 50, mode=Qt.SmoothTransformation) self._life_bar_width = int(self._ship_alive.width()) self._life_bar_xy = np.array( [self._life_bar_width // 2, self._ship_alive.height() // 2 + 25]) self._life_bar_height = 2 self.debug = 0 self.is_set = True def paint(self, painter: QPainter, model: ShipModel = None): assert self.is_set, 'Painter is not set' # Draw ship if model.is_alive: _ship = self._ship_alive else: _ship = self._ship_dead _pixmap = _ship.transformed(model.transform, mode=Qt.SmoothTransformation) _center_ship = self.transform(model.x - _pixmap.width() / 2, model.y + _pixmap.height() / 2, is_point=True) if 0 <= _center_ship.x() <= self.parent.width( ) and 0 <= _center_ship.y() <= self.parent.height(): painter.drawPixmap(_center_ship, _pixmap) # Draw life bar _center_bar = self.transform(model.x - self._life_bar_xy[0], model.y + self._life_bar_xy[1], is_point=True) painter.setPen(QPen(QColor(255, 0, 0), 0, Qt.NoPen)) painter.setBrush(QBrush(QColor(255, 0, 0))) painter.drawRect(_center_bar.x(), _center_bar.y(), self._life_bar_width, 5) painter.setBrush(QBrush(QColor(0, 255, 0))) painter.drawRect(_center_bar.x(), _center_bar.y(), int(self._life_bar_width * model.life), 5) painter.setPen(QPen(QColor(*model.color), 5, Qt.SolidLine)) _center_title = self.transform(model.x - 100, model.y + 70, is_point=True) painter.setFont( QFont('Open Sans', weight=QFont.Normal, pointSize=8)) painter.drawText( QRect(_center_title.x(), _center_title.y(), 200, 25), Qt.AlignHCenter | Qt.AlignTop, '<{}>'.format(model.name)) painter.setBrush(QBrush(QColor(*model.color))) _center_point = self.transform(model.x, model.y, is_point=True) painter.drawPoint(_center_point) else: _xy = QPoint(_center_ship) if _center_ship.x() < 0: _xy.setX(0) if self.parent.width() < _center_ship.x(): _xy.setX(self.parent.width()) if _center_ship.y() < 0: _xy.setY(0) if self.parent.height() < _center_ship.y(): _xy.setY(self.parent.height()) painter.setPen(QPen(QColor(0, 0, 0), 30, Qt.SolidLine, Qt.RoundCap)) painter.drawPoint(_xy) painter.setPen( QPen(QColor(*model.color), 25, Qt.SolidLine, Qt.RoundCap)) painter.drawPoint(_xy)
class ButtonIcon(QPushButton): def __init__(self, label=None, icon="", iconsize=40, inactive=(255, 255, 255), active=(255, 0, 0), duration=300): super(ButtonIcon, self).__init__() self.activeColor = QColor(active[0], active[1], active[2]) self.inactiveColor = QColor(inactive[0], inactive[1], inactive[2]) self.animDuration = duration self.iconResolution = iconsize self.setStyleSheet("background-color : transparent;") self.setFixedSize(self.iconResolution + 5, self.iconResolution + 5) self.setCursor(QCursor(Qt.PointingHandCursor)) self.changeIcon(icon) if hasattr(self, "px_mask"): self.px.fill(self.inactiveColor) self.px.setMask(self.px_mask) self.setIcon(QIcon(self.px)) self.setIconSize(QSize(self.iconResolution, self.iconResolution)) if isinstance(label, str): font = self.font() font.setPointSize(self.iconResolution / 10) self.setFont(font) self.setText(label) if self.px: self.setColor(self.inactiveColor) self.hoverAnimation = self.animate(self.inactiveColor, self.activeColor, self.animDuration, self.animationCallback) self.leaveAnimation = self.animate(self.activeColor, self.inactiveColor, self.animDuration, self.animationCallback) def setHeight(self, value): self.setFixedHeight(value) self.setFixedWidth(value) def getHeight(self): return self.height() Height = Property(int, getHeight, setHeight) def changeIcon(self, path): self.iconPath = path if os.path.isfile(self.iconPath): self.px = QPixmap(self.iconPath) self.px.scaled(self.iconResolution, self.iconResolution, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.px_mask = self.px.createMaskFromColor(QColor('transparent')) self.event(QEvent(QEvent.Type.MouseButtonRelease)) self.update() def setColor(self, value): self.__color = value self.px.fill(self.__color) self.px.setMask(self.px_mask) self.setIcon(QIcon(self.px)) def getColor(self): return self.__color color = Property(QColor, getColor, setColor) def animationCallback(self, state): if state == QAbstractAnimation.State.Stopped: self.hoverAnimation = self.animate(self.inactiveColor, self.activeColor, self.animDuration, self.animationCallback) self.leaveAnimation = self.animate(self.activeColor, self.inactiveColor, self.animDuration, self.animationCallback) def animate(self, start, end, duration, callback): ani = QPropertyAnimation(self, b"color") ani.setStartValue(start) ani.setEndValue(end) ani.setDuration(duration) ani.stateChanged.connect(callback) return ani def event(self, event): if event.type() == QEvent.Type.Enter: if self.leaveAnimation.state() == QAbstractAnimation.State.Running: self.leaveAnimation.stop() current = sum([ self.getColor().redF(), self.getColor().greenF(), self.getColor().blueF() ]) target = sum([ self.activeColor.redF(), self.activeColor.greenF(), self.activeColor.blueF() ]) self.hoverAnimation = self.animate( self.getColor(), self.activeColor, max(target - current, 0) * self.animDuration, self.animationCallback) self.hoverAnimation.start() elif event.type() == QEvent.Type.Leave: if self.hoverAnimation.state() == QAbstractAnimation.State.Running: self.hoverAnimation.stop() current = max([ self.getColor().redF(), self.getColor().greenF(), self.getColor().blueF() ]) target = max([ self.inactiveColor.redF(), self.inactiveColor.greenF(), self.inactiveColor.blueF() ]) self.leaveAnimation = self.animate( self.getColor(), self.inactiveColor, max(current - target, 0) * self.animDuration, self.animationCallback) self.leaveAnimation.start() elif event.type() in [ QEvent.Type.MouseButtonPress, QEvent.Type.MouseButtonDblClick ]: pressColor = QColor( (self.inactiveColor.red() + self.activeColor.red()) / 2, (self.inactiveColor.green() + self.activeColor.green()) / 2, (self.inactiveColor.blue() + self.activeColor.blue()) / 2) self.px.fill(pressColor) self.px.setMask(self.px_mask) self.setIcon(QIcon(self.px)) elif event.type() == QEvent.Type.MouseButtonRelease: self.px.fill(self.activeColor) self.px.setMask(self.px_mask) self.setIcon(QIcon(self.px)) return super(ButtonIcon, self).event(event)
class ImageLabel(QLabel): def __init__(self, parent, label_img_size, brush_color, eraser_color): super(ImageLabel, self).__init__(parent) self.label_img = None self.mask_img = None self.mask_img_path = None self.label_img_size = label_img_size self.img_rect = QRect( QPoint(0, 0), QPoint(self.label_img_size.width(), self.label_img_size.height())) self.mask_img = QPixmap(self.label_img_size) self.mask_img.fill(QColor(255, 255, 255)) self.mouse_press_flag = False self.mouse_pos = None self.eraser_painting_model = False self.brush_pixle_size = 5 self.eraser_pixle_size = 5 self.brush_color = brush_color self.eraser_color = eraser_color self.brush_model_cursor = None self.eraser_model_cursor = None self.update_brush_pixle_size(self.brush_pixle_size) self.update_eraser_pixle_size(self.eraser_pixle_size) self.setCursor(self.brush_model_cursor) def update_brush_color(self, color): self.brush_color = color self.update_brush_pixle_size(self.brush_pixle_size) def update_brush_pixle_size(self, pixle_size): self.brush_pixle_size = pixle_size brush_cursor_pix = QPixmap( QSize(self.brush_pixle_size, self.brush_pixle_size)) brush_cursor_pix.fill(QColor(0, 0, 0)) brush_cursor_pix_painter = QPainter(brush_cursor_pix) brush_cursor_pix_painter.setBrush(self.brush_color) brush_cursor_pix_painter.drawEllipse( QRect(QPoint(-2, -2), QPoint(self.brush_pixle_size, self.brush_pixle_size))) brush_cursor_pix_painter.end() brush_cursor_pix.setMask( brush_cursor_pix.createMaskFromColor(self.brush_color, Qt.MaskOutColor)) self.brush_model_cursor = QCursor(brush_cursor_pix) if not self.eraser_painting_model: self.setCursor(self.brush_model_cursor) def update_eraser_pixle_size(self, pixle_size): self.eraser_pixle_size = pixle_size eraser_cursor_pix = QPixmap( QSize(self.eraser_pixle_size, self.eraser_pixle_size)) eraser_cursor_pix.fill(QColor(255, 255, 255)) eraser_cursor_pix_painter = QPainter(eraser_cursor_pix) eraser_cursor_pix_painter.setBrush(self.eraser_color) eraser_cursor_pix_painter.drawEllipse( QRect(QPoint(-2, -2), QPoint(self.eraser_pixle_size, self.eraser_pixle_size))) eraser_cursor_pix_painter.end() eraser_cursor_pix.setMask( eraser_cursor_pix.createMaskFromColor(self.eraser_color, Qt.MaskOutColor)) self.eraser_model_cursor = QCursor(eraser_cursor_pix) if self.eraser_painting_model: self.setCursor(self.eraser_model_cursor) def update_label_img(self, label_img, mask_img, mask_img_path): self.label_img = label_img.scaled(self.label_img_size) self.mask_img = mask_img self.mask_img.setMask( self.mask_img.createMaskFromColor(self.brush_color, Qt.MaskOutColor)) self.mask_img_path = mask_img_path self.update() def join_pixmap(self, p1, p2): result = QPixmap(p1.size()) result.fill(QtCore.Qt.transparent) painter = QPainter(result) painter.setRenderHint(QPainter.Antialiasing) painter.setCompositionMode(QPainter.CompositionMode_Source) painter.drawPixmap(QtCore.QPoint(), p1) painter.setCompositionMode(QPainter.CompositionMode_Overlay) painter.drawPixmap(QtCore.QPoint(), p2) painter.end() return result def mousePressEvent(self, event): if event.button() == QtCore.Qt.LeftButton: if QApplication.keyboardModifiers() == QtCore.Qt.AltModifier: self.eraser_painting_model = True self.setCursor(self.eraser_model_cursor) else: self.eraser_painting_model = False self.setCursor(self.brush_model_cursor) self.mouse_press_flag = True self.mouse_pos = event.pos() self.update() def mouseMoveEvent(self, event): if not self.mouse_press_flag: return if QApplication.keyboardModifiers() == QtCore.Qt.AltModifier: self.eraser_painting_model = True self.setCursor(self.eraser_model_cursor) else: self.eraser_painting_model = False self.setCursor(self.brush_model_cursor) self.mouse_pos = event.pos() self.update() def mouseReleaseEvent(self, event): if self.mask_img: self.mask_img.save(self.mask_img_path) if not self.mouse_press_flag: return if event.button() == QtCore.Qt.LeftButton: self.mouse_press_flag = False self.mouse_pos = None self.eraser_painting_model = False self.setCursor(self.brush_model_cursor) self.parent().show_label_img() def paintEvent(self, QPaintEvent): painter = QPainter() painter.begin(self) painter.setPen(Qt.NoPen) painter.fillRect(self.rect(), QColor(190, 190, 190, 255)) if self.label_img: if self.mouse_press_flag and self.mouse_pos: pp = QPainter(self.mask_img) if self.eraser_painting_model: pp.setPen( QPen(self.eraser_color, self.eraser_pixle_size, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin)) else: pp.setPen( QPen(self.brush_color, self.brush_pixle_size, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin)) pp.drawPoint(self.mouse_pos - self.img_rect.topLeft()) result_pixmap = self.join_pixmap(self.label_img, self.mask_img) painter.drawPixmap(self.img_rect, result_pixmap) painter.end() def resizeEvent(self, event): x = (self.size().width() - self.label_img_size.width()) // 2 y = (self.size().height() - self.label_img_size.height()) // 2 self.img_rect = QRect( QPoint(x, y), QPoint(self.label_img_size.width() + x, self.label_img_size.height() + y))