class CustomGraphicsView(QGraphicsView): def __init__(self, parent): super().__init__(parent) self.pen = QPen(Qt.green, 3, join=Qt.MiterJoin) self.item_batch = [] self.item_batches = collections.deque() def wheelEvent(self, event): if self.scene() and QApplication.keyboardModifiers( ) == Qt.ControlModifier: transform = self.transform() scale = 1 + ZOOM_FACTOR if event.angleDelta().y( ) > 0 else 1 - ZOOM_FACTOR self.setTransform(transform * scale) def mousePressEvent(self, event): if not self.scene(): return position = self.mapToScene(event.x(), event.y()) item = self.scene().addRect(position.x(), position.y(), self.pen.width(), self.pen.width(), self.pen, self.pen.brush()) self.item_batch.append(item) # TODO: Calculate line between new and last-known position, and draw a rectangle for each point on the line, # TODO: addLine() seems to add a different-looking pattern def mouseMoveEvent(self, event): self.mousePressEvent(event) def mouseReleaseEvent(self, event): if self.item_batch: self.item_batches.append(self.item_batch) self.item_batch = [] # TODO: This is super ugly because we don't use addLine() def undo(self): if not self.item_batches: return item_batch = self.item_batches.pop() scene = self.scene() for item in item_batch: scene.removeItem(item)
def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionGraphicsItem', widget: QWidget = None): print(option.levelOfDetailFromTransform(painter.worldTransform())) painter.save() pen = QPen(Qt.red) pen.setWidth(0) painter.setPen(pen) brush = pen.brush() for i in range(200 - 1): height = data['high'][i] - data['low'][i] painter.fillRect( QRectF(i * 3, data['high'][i] - data['high'].min(), 1, height), brush) painter.fillRect(QRectF(100, 100, 100, -100), Qt.blue) painter.restore()
def paint(self, painter, option, widget): painter.save() painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing == ANTIALIASING_FULL)) selected = self.isSelected() theme = canvas.theme if self.m_port_type == PORT_TYPE_AUDIO_JACK: poly_color = theme.port_audio_jack_bg_sel if selected else theme.port_audio_jack_bg poly_pen = theme.port_audio_jack_pen_sel if selected else theme.port_audio_jack_pen text_pen = theme.port_audio_jack_text_sel if selected else theme.port_audio_jack_text conn_pen = QPen(theme.port_audio_jack_pen_sel) elif self.m_port_type == PORT_TYPE_MIDI_JACK: poly_color = theme.port_midi_jack_bg_sel if selected else theme.port_midi_jack_bg poly_pen = theme.port_midi_jack_pen_sel if selected else theme.port_midi_jack_pen text_pen = theme.port_midi_jack_text_sel if selected else theme.port_midi_jack_text conn_pen = QPen(theme.port_midi_jack_pen_sel) elif self.m_port_type == PORT_TYPE_MIDI_ALSA: poly_color = theme.port_midi_alsa_bg_sel if selected else theme.port_midi_alsa_bg poly_pen = theme.port_midi_alsa_pen_sel if selected else theme.port_midi_alsa_pen text_pen = theme.port_midi_alsa_text_sel if selected else theme.port_midi_alsa_text conn_pen = QPen(theme.port_midi_alsa_pen_sel) elif self.m_port_type == PORT_TYPE_PARAMETER: poly_color = theme.port_parameter_bg_sel if selected else theme.port_parameter_bg poly_pen = theme.port_parameter_pen_sel if selected else theme.port_parameter_pen text_pen = theme.port_parameter_text_sel if selected else theme.port_parameter_text conn_pen = QPen(theme.port_parameter_pen_sel) else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid port type '%s'" % port_type2str(self.m_port_type)) return # To prevent quality worsening poly_pen = QPen(poly_pen) poly_pen.setWidthF(poly_pen.widthF() + 0.00001) if self.m_is_alternate: poly_color = poly_color.darker(180) #poly_pen.setColor(poly_pen.color().darker(110)) #text_pen.setColor(text_pen.color()) #.darker(150)) #conn_pen.setColor(conn_pen.color()) #.darker(150)) lineHinting = poly_pen.widthF() / 2 poly_locx = [0, 0, 0, 0, 0] poly_corner_xhinting = (float(canvas.theme.port_height) / 2) % floor( float(canvas.theme.port_height) / 2) if poly_corner_xhinting == 0: poly_corner_xhinting = 0.5 * ( 1 - 7 / (float(canvas.theme.port_height) / 2)) if self.m_port_mode == PORT_MODE_INPUT: text_pos = QPointF(3, canvas.theme.port_text_ypos) if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON: poly_locx[0] = lineHinting poly_locx[1] = self.m_port_width + 5 - lineHinting poly_locx[2] = self.m_port_width + 12 - poly_corner_xhinting poly_locx[3] = self.m_port_width + 5 - lineHinting poly_locx[4] = lineHinting elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE: poly_locx[0] = lineHinting poly_locx[1] = self.m_port_width + 5 - lineHinting poly_locx[2] = self.m_port_width + 5 - lineHinting poly_locx[3] = self.m_port_width + 5 - lineHinting poly_locx[4] = lineHinting else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'" % canvas.theme.port_mode) return elif self.m_port_mode == PORT_MODE_OUTPUT: text_pos = QPointF(9, canvas.theme.port_text_ypos) if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON: poly_locx[0] = self.m_port_width + 12 - lineHinting poly_locx[1] = 7 + lineHinting poly_locx[2] = 0 + poly_corner_xhinting poly_locx[3] = 7 + lineHinting poly_locx[4] = self.m_port_width + 12 - lineHinting elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE: poly_locx[0] = self.m_port_width + 12 - lineHinting poly_locx[1] = 5 + lineHinting poly_locx[2] = 5 + lineHinting poly_locx[3] = 5 + lineHinting poly_locx[4] = self.m_port_width + 12 - lineHinting else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'" % canvas.theme.port_mode) return else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid port mode '%s'" % port_mode2str(self.m_port_mode)) return polygon = QPolygonF() polygon += QPointF(poly_locx[0], lineHinting) polygon += QPointF(poly_locx[1], lineHinting) polygon += QPointF(poly_locx[2], float(canvas.theme.port_height) / 2) polygon += QPointF(poly_locx[3], canvas.theme.port_height - lineHinting) polygon += QPointF(poly_locx[4], canvas.theme.port_height - lineHinting) polygon += QPointF(poly_locx[0], lineHinting) if canvas.theme.port_bg_pixmap: portRect = polygon.boundingRect().adjusted(-lineHinting + 1, -lineHinting + 1, lineHinting - 1, lineHinting - 1) portPos = portRect.topLeft() painter.drawTiledPixmap(portRect, canvas.theme.port_bg_pixmap, portPos) else: painter.setBrush(poly_color) #.lighter(200)) painter.setPen(poly_pen) painter.drawPolygon(polygon) painter.setPen(text_pen) painter.setFont(self.m_port_font) painter.drawText(text_pos, self.m_port_name) if canvas.theme.idx == Theme.THEME_OOSTUDIO and canvas.theme.port_bg_pixmap: conn_pen.setCosmetic(True) conn_pen.setWidthF(0.4) painter.setPen(conn_pen) if self.m_port_mode == PORT_MODE_INPUT: connLineX = portRect.left() + 1 else: connLineX = portRect.right() - 1 conn_path = QPainterPath() conn_path.addRect( QRectF(connLineX - 1, portRect.top(), 2, portRect.height())) painter.fillPath(conn_path, conn_pen.brush()) painter.drawLine( QLineF(connLineX, portRect.top(), connLineX, portRect.bottom())) painter.restore()
class CollapseExpandButton(QPushButton): def _buildPainterPaths(self, size): marginLR = int(math.floor((size.width() * 0.3) + 0.5)) marginUD = int(math.floor((size.height() * 0.3) + 0.5)) middleColl = int(math.floor((size.height() / 2.0) + 0.5)) middleExpd = int(math.floor((size.width() / 2.0) + 0.5)) self._collapsedPath = QPainterPath( QPointF(size.width() - marginLR, marginUD)) self._collapsedPath.lineTo(marginLR, middleColl) self._collapsedPath.lineTo(size.width() - marginLR, size.height() - marginUD) self._expandedPath = QPainterPath(QPointF(marginLR, marginUD)) self._expandedPath.lineTo(middleExpd, size.height() - marginUD) self._expandedPath.lineTo(size.width() - marginLR, marginUD) @pyqtSlot() def _onClicked(self): if self._currentState == State.COLLAPSED: self._currentState = State.EXPANDED self.collapsedExpanded.emit(Transition.EXPAND) elif self._currentState == State.EXPANDED: self._currentState = State.COLLAPSED self.collapsedExpanded.emit(Transition.COLLAPSE) super().update() def __init__(self, parent=None): super().__init__(parent) super().setText('') self._currentState = State.EXPANDED pal = self.palette() self._pen = QPen(pal.color(QPalette.WindowText)) self._pen.setWidth(2) self._collapsedPath = None self._expandedPath = None self._buildPainterPaths(self.size()) self.clicked.connect(self._onClicked) collapsedExpanded = pyqtSignal(Transition) def paintEvent(self, ev): super().paintEvent(ev) p = QPainter(self) p.setPen(self._pen) p.setRenderHint(QPainter.Antialiasing, True) if self._currentState == State.COLLAPSED: p.fillPath(self._collapsedPath, self._pen.brush()) elif self._currentState == State.EXPANDED: p.fillPath(self._expandedPath, self._pen.brush()) def resizeEvent(self, ev): self._buildPainterPaths(ev.size()) def setState(self, state): self._currentState = state self.repaint() def state(self): return self._currentState
def paint(self, painter, option, widget): if canvas.scene.loading_items: return painter.save() painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing == ANTIALIASING_FULL)) selected = self.isSelected() theme = canvas.theme if self.m_port_type == PORT_TYPE_AUDIO_JACK: if self.m_is_alternate: poly_color = theme.port_cv_jack_bg_sel if selected else theme.port_cv_jack_bg poly_pen = theme.port_cv_jack_pen_sel if selected else theme.port_cv_jack_pen else: poly_color = theme.port_audio_jack_bg_sel if selected else theme.port_audio_jack_bg poly_pen = theme.port_audio_jack_pen_sel if selected else theme.port_audio_jack_pen text_pen = theme.port_audio_jack_text_sel if selected else theme.port_audio_jack_text conn_pen = QPen(theme.port_audio_jack_pen_sel) elif self.m_port_type == PORT_TYPE_MIDI_JACK: poly_color = theme.port_midi_jack_bg_sel if selected else theme.port_midi_jack_bg poly_pen = theme.port_midi_jack_pen_sel if selected else theme.port_midi_jack_pen text_pen = theme.port_midi_jack_text_sel if selected else theme.port_midi_jack_text conn_pen = QPen(theme.port_midi_jack_pen_sel) elif self.m_port_type == PORT_TYPE_MIDI_ALSA: poly_color = theme.port_midi_alsa_bg_sel if selected else theme.port_midi_alsa_bg poly_pen = theme.port_midi_alsa_pen_sel if selected else theme.port_midi_alsa_pen text_pen = theme.port_midi_alsa_text_sel if selected else theme.port_midi_alsa_text conn_pen = QPen(theme.port_midi_alsa_pen_sel) elif self.m_port_type == PORT_TYPE_PARAMETER: poly_color = theme.port_parameter_bg_sel if selected else theme.port_parameter_bg poly_pen = theme.port_parameter_pen_sel if selected else theme.port_parameter_pen text_pen = theme.port_parameter_text_sel if selected else theme.port_parameter_text conn_pen = QPen(theme.port_parameter_pen_sel) else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid port type '%s'" % port_type2str(self.m_port_type)) return # To prevent quality worsening poly_pen = QPen(poly_pen) poly_pen.setWidthF(poly_pen.widthF() + 0.00001) lineHinting = poly_pen.widthF() / 2 poly_locx = [0, 0, 0, 0, 0, 0] poly_corner_xhinting = ((float(canvas.theme.port_height) / 2) % floor(float(canvas.theme.port_height) / 2)) if poly_corner_xhinting == 0: poly_corner_xhinting = 0.5 * ( 1 - 7 / (float(canvas.theme.port_height) / 2)) is_cv_port = bool(self.m_port_type == PORT_TYPE_AUDIO_JACK and self.m_is_alternate) if self.m_port_mode == PORT_MODE_INPUT: text_pos = QPointF(3, canvas.theme.port_text_ypos) if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON and not is_cv_port: poly_locx[0] = lineHinting poly_locx[1] = self.m_port_width + 5 - lineHinting poly_locx[2] = self.m_port_width + 12 - poly_corner_xhinting poly_locx[3] = self.m_port_width + 5 - lineHinting poly_locx[4] = lineHinting poly_locx[5] = self.m_port_width elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE or is_cv_port: poly_locx[0] = lineHinting poly_locx[1] = self.m_port_width + 5 - lineHinting poly_locx[2] = self.m_port_width + 5 - lineHinting poly_locx[3] = self.m_port_width + 5 - lineHinting poly_locx[4] = lineHinting poly_locx[5] = self.m_port_width else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'" % canvas.theme.port_mode) return elif self.m_port_mode == PORT_MODE_OUTPUT: text_pos = QPointF(9, canvas.theme.port_text_ypos) if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON and not is_cv_port: poly_locx[0] = self.m_port_width + 12 - lineHinting poly_locx[1] = 7 + lineHinting poly_locx[2] = 0 + poly_corner_xhinting poly_locx[3] = 7 + lineHinting poly_locx[4] = self.m_port_width + 12 - lineHinting poly_locx[5] = 12 - lineHinting elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE or is_cv_port: poly_locx[0] = self.m_port_width + 12 - lineHinting poly_locx[1] = 5 + lineHinting poly_locx[2] = 5 + lineHinting poly_locx[3] = 5 + lineHinting poly_locx[4] = self.m_port_width + 12 - lineHinting poly_locx[5] = 12 - lineHinting else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'" % canvas.theme.port_mode) return else: qCritical( "PatchCanvas::CanvasPort.paint() - invalid port mode '%s'" % port_mode2str(self.m_port_mode)) return polygon = QPolygonF() if self.m_portgrp_id: first_of_portgrp = False last_of_portgrp = False # look in portgroup if port is the first, # the last, or not. for portgrp in canvas.portgrp_list: if portgrp.portgrp_id == self.m_portgrp_id: if self.m_port_id == portgrp.port_id_list[0]: first_of_portgrp = True if self.m_port_id == portgrp.port_id_list[-1]: last_of_portgrp = True break if first_of_portgrp: polygon += QPointF(poly_locx[0], lineHinting) polygon += QPointF(poly_locx[5], lineHinting) else: polygon += QPointF(poly_locx[0], 0) polygon += QPointF(poly_locx[5], 0) if last_of_portgrp: polygon += QPointF(poly_locx[5], canvas.theme.port_height - lineHinting) polygon += QPointF(poly_locx[0], canvas.theme.port_height - lineHinting) else: polygon += QPointF(poly_locx[5], canvas.theme.port_height) polygon += QPointF(poly_locx[0], canvas.theme.port_height) else: polygon += QPointF(poly_locx[0], lineHinting) polygon += QPointF(poly_locx[1], lineHinting) polygon += QPointF(poly_locx[2], float(canvas.theme.port_height) / 2) polygon += QPointF(poly_locx[3], canvas.theme.port_height - lineHinting) polygon += QPointF(poly_locx[4], canvas.theme.port_height - lineHinting) polygon += QPointF(poly_locx[0], lineHinting) if canvas.theme.port_bg_pixmap: portRect = polygon.boundingRect().adjusted(-lineHinting + 1, -lineHinting + 1, lineHinting - 1, lineHinting - 1) portPos = portRect.topLeft() painter.drawTiledPixmap(portRect, canvas.theme.port_bg_pixmap, portPos) else: port_gradient = QLinearGradient(0, 0, 0, self.m_port_height) dark_color = poly_color.darker(112) light_color = poly_color.lighter(111) if poly_color.lightness() > 127: port_gradient.setColorAt(0, dark_color) port_gradient.setColorAt(0.5, light_color) port_gradient.setColorAt(1, dark_color) else: port_gradient.setColorAt(0, light_color) port_gradient.setColorAt(0.5, dark_color) port_gradient.setColorAt(1, light_color) painter.setBrush(port_gradient) painter.setPen(poly_pen) painter.drawPolygon(polygon) if self.m_is_alternate and not self.m_portgrp_id: if is_cv_port: poly_pen.setWidthF(2.000001) painter.setPen(poly_pen) y_line = canvas.theme.port_height / 2.0 if self.m_port_mode == PORT_MODE_OUTPUT: painter.drawLine(QPointF(0.0, y_line), QPointF(float(poly_locx[1]), y_line)) elif self.m_port_mode == PORT_MODE_INPUT: painter.drawLine(QPointF(self.m_port_width + 5.0, y_line), QPointF(self.m_port_width + 12.0, y_line)) else: # draw the little circle for a2j (or MidiBridge) port poly_pen.setWidthF(1.000001) painter.setBrush(canvas.theme.box_bg_1) ellipse_x = poly_locx[1] if self.m_port_mode == PORT_MODE_OUTPUT: ellipse_x -= 2 elif self.m_port_mode == PORT_MODE_INPUT: ellipse_x += 2 painter.drawEllipse( QPointF(ellipse_x, canvas.theme.port_height / 2.0), 2, 2) painter.setPen(text_pen) painter.setFont(self.m_port_font) sizer = QFontMetrics(self.m_port_font) sep_width = sizer.width(self.m_trunck_sep) if self.m_portgrp_id: print_name_size = self.get_text_width() if self.m_port_mode == PORT_MODE_OUTPUT: text_pos = QPointF(self.m_port_width + 9 - print_name_size, canvas.theme.port_text_ypos) if print_name_size > (self.m_port_width - 4): painter.setPen(QPen(port_gradient, 3)) painter.drawLine( QPointF(float(poly_locx[5]), 3.0), QPointF(float(poly_locx[5]), canvas.theme.port_height - 3.0)) painter.setPen(text_pen) painter.setFont(self.m_port_font) painter.drawText(text_pos, self.m_print_name) if self.m_name_truncked: sep_x = text_pos.x() + sizer.width(self.m_print_name) painter.drawText(QPointF(sep_x + sep_width, text_pos.y()), self.m_print_name_right) painter.setPen(poly_pen) painter.drawText(QPointF(sep_x, text_pos.y() + 1), self.m_trunck_sep) if canvas.theme.idx == Theme.THEME_OOSTUDIO and canvas.theme.port_bg_pixmap: painter.setPen(Qt.NoPen) painter.setBrush(conn_pen.brush()) if self.m_port_mode == PORT_MODE_INPUT: connRect = QRectF(portRect.topLeft(), QSizeF(2, portRect.height())) else: connRect = QRectF( QPointF(portRect.right() - 2, portRect.top()), QSizeF(2, portRect.height())) painter.drawRect(connRect) painter.restore()