def updateSceneRect(self, factor: float) -> QRectF: """Updates the associated scene's bounding rectangle. To make it possible to pan the view, the scene's bounding rectangle must be larger than the viewport. Scaling the view means that the scene in its entirety is scaled, including the scene's bounding rectangle, so it must be scaled along with the view. Currently, the view can be panned such that the editing grid can be freely moved around, but within the bounds of the viewport regardless of its size or zoom level, similar to Aseprite. Args: factor: The scaling factor the scene should be sized with respect to. Returns the updated scene bounding rectangle. """ # TODO: make configurable via Property margin = QSize(10, 10) # Between edge of grid and viewport editAreaRect = self.editor().editArea.rect() editAreaSize = editAreaRect.size().toSize() # Make the scene 2x larger than the viewport, minus the editing grid. This # allows us to pan the grid up to the edges of the viewport (minus margin), # but no further. Also ensure the scene is at least big enough to encompass # the entire grid. sceneSize = self.maximumViewportSize() * 2 * (1 / factor) sceneSize = sceneSize - editAreaSize - margin sceneSize = sceneSize.expandedTo(editAreaSize + margin) newSceneRect = QRectF(QPointF(0, 0), sceneSize) newSceneRect.moveCenter(editAreaRect.center()) self.setSceneRect(newSceneRect) return newSceneRect
def _make_ellipse_path(self): """Returns an ellipse path for the link's base. Returns: QPainterPath """ ellipse_path = QPainterPath() rect = QRectF(0, 0, 1.6 * self.magic_number, 1.6 * self.magic_number) rect.moveCenter(self.src_center) ellipse_path.addEllipse(rect) return ellipse_path
def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(painter.Antialiasing) #painter.setBrush(QBrush(Qt.black, Qt.NoBrush)) #painter.drawRect(self.winBox) # border # value selector indicator painter.setBrush(QBrush(Qt.black, Qt.SolidPattern)) painter.drawPie(self.vIdBox, 16 * (degrees(self.vIdAng) - 22.5), 720) # value selector arc painter.setClipPath(self.vArcPath) painter.setPen(Qt.NoPen) arc = QConicalGradient(self.cen, self.e_ang) color = QColor() color.setHsv(self.hue, self.sat, 255) arc.setColorAt(1 - (self.e_ang - self.s_ang) / 360.0, color) arc.setColorAt(1, Qt.black) arc.setColorAt(0, Qt.black) painter.setBrush(arc) painter.drawPath(self.vArcPath) painter.setClipPath(self.vArcPath, Qt.NoClip) # color wheel painter.setPen(Qt.NoPen) painter.setBrush(self.cWhlBrush1) painter.drawEllipse(self.cWhBox) painter.setBrush(self.cWhlBrush2) painter.drawEllipse(self.cWhBox) # crosshairs painter.setClipPath(self.colWhlPath) painter.setBrush(QBrush(Qt.black, Qt.SolidPattern)) chVert = QRectF(0, 0, 2, 20) chHort = QRectF(0, 0, 20, 2) chVert.moveCenter(self.chPt) chHort.moveCenter(self.chPt) painter.drawRect(chVert) painter.drawRect(chHort) # named color locations if self._showNames: painter.setClipPath(self.vArcPath, Qt.NoClip) painter.setPen(Qt.SolidLine) try: painter.drawPoints(*self._namedColorPts) # PyQt except: painter.drawPoints(self._namedColorPts) # PySide
def __init__(self, parent, toolbox, position="left"): """Connector button graphics item. Used for Link drawing between project items. Args: parent (QGraphicsItem): Project item bg rectangle toolbox (ToolBoxUI): QMainWindow instance position (str): Either "top", "left", "bottom", or "right" """ super().__init__(parent) self._parent = parent self._toolbox = toolbox self.position = position self.links = list() pen = QPen(Qt.black, 0.5, Qt.SolidLine) self.setPen(pen) self.setBrush(self.brush) parent_rect = parent.rect() extent = 0.2 * parent_rect.width() rect = QRectF(0, 0, extent, extent) if position == "top": rect.moveCenter( QPointF(parent_rect.center().x(), parent_rect.top() + extent / 2)) elif position == "left": rect.moveCenter( QPointF(parent_rect.left() + extent / 2, parent_rect.center().y())) elif position == "bottom": rect.moveCenter( QPointF(parent_rect.center().x(), parent_rect.bottom() - extent / 2)) elif position == "right": rect.moveCenter( QPointF(parent_rect.right() - extent / 2, parent_rect.center().y())) self.setRect(rect) self.setAcceptHoverEvents(True) self.setCursor(Qt.PointingHandCursor)
def paint(self, painter, option, widget=None): if Design.flow_theme == 'dark std': color = QColor( '#2E688C' ) if self.parent_port_instance.type_ == 'data' else QColor( '#3880ad') if option.state & QStyle.State_MouseOver: color = color.lighter() brush = QBrush(QColor(color)) painter.setBrush(brush) painter.setPen(Qt.NoPen) painter.drawEllipse( QRectF(self.padding, self.padding, self.painting_width, self.painting_height)) elif Design.flow_theme == 'dark tron': color = '' if self.parent_port_instance.type_ == 'exec': color = '#FFFFFF' elif self.parent_port_instance.type_ == 'data': color = self.parent_node_instance.parent_node.color pen = QPen(color) pen.setWidth(2) painter.setPen(pen) if len(self.parent_port_instance.connected_port_instances) > 0 or \ option.state & QStyle.State_MouseOver: # also fill when mouse hovers c = self.parent_node_instance.parent_node.color r = c.red() g = c.green() b = c.blue() brush = QBrush(QColor(r, g, b, 100)) painter.setBrush(brush) else: painter.setBrush(Qt.NoBrush) painter.drawEllipse( QRectF(self.padding, self.padding, self.painting_width, self.painting_height)) elif Design.flow_theme == 'ghostly' or Design.flow_theme == 'blender': color = '' if self.parent_port_instance.type_ == 'exec': color = '#FFFFFF' if len(self.parent_port_instance.connected_port_instances) > 0 or \ option.state & QStyle.State_MouseOver: # also fill when mouse hovers brush = QBrush(QColor(255, 255, 255, 100)) painter.setBrush(brush) else: painter.setBrush(Qt.NoBrush) elif self.parent_port_instance.type_ == 'data': color = self.parent_node_instance.parent_node.color if len(self.parent_port_instance.connected_port_instances) > 0 or \ option.state & QStyle.State_MouseOver: # also fill when mouse hovers c = self.parent_node_instance.parent_node.color r = c.red() g = c.green() b = c.blue() brush = QBrush(QColor(r, g, b, 100)) painter.setBrush(brush) else: painter.setBrush(Qt.NoBrush) pen = QPen(color) pen.setWidth(1) painter.setPen(pen) rect = QRectF() rect.moveCenter(QPointF(self.width / 2, self.height / 2)) rect.setWidth(self.painting_width) rect.setHeight(self.painting_height) painter.drawEllipse(QPointF(self.width / 2, self.height / 2), self.painting_width / 3, self.painting_height / 3)
class wheel(QWidget): currentColorChanged = Signal(QColor) def __init__(self, parent=None): super(wheel, self).__init__(parent) self.setFixedSize(256, 256) # start, end angles for value arc self.s_ang, self.e_ang = 135, 225 # offset angle and direction for color wheel self.o_ang, self.rot_d = 45, -1 # 1 for clock-wise, -1 for widdershins # other initializations self.pos = QPointF(-100, -100) self.vIdCen = QPointF(-100, -100) self.vIdAng = radians(self.s_ang) self.chPt = self.pos self.hue = self.sat = self.value = 255 self.setup() self.pos = self.cWhBox.center() self._namedColorList = [] self._namedColorPts = [] self._showNames = False self.setMouseTracking(True) self.installEventFilter(self) self._startedTimer = False ## def timerSpinner(self): ## "won't this be fun" ## self.o_ang -= 1; self.o_ang %= 360 ## stable = False ## ## colWhl = QConicalGradient(self.cen, self.o_ang) ## whl_cols = [Qt.red, Qt.magenta, ## Qt.blue, Qt.cyan, Qt.green, ## Qt.yellow, Qt.red] ## for i, c in enumerate(whl_cols[::self.rot_d]): ## colWhl.setColorAt(i / 6.0, c) ## ## if stable: # crosshairs stay on color ## t = radians(self.hue + self.o_ang * -self.rot_d) * -self.rot_d ## r = self.sat / 255.0 * self.cW_rad ## x, y = r * cos(t) + self.cen.x(), r * -sin(t) + self.cen.y() ## self.chPt = QPointF(x, y) ## else: # crosshairs stay on point ## t = atan2(self.cen.y() - self.pos.y(), self.pos.x() - self.cen.x()) ## h = (int(degrees(t)) - self.o_ang) * -self.rot_d ## self.hue = (h if h > 0 else h + 360) % 360 ## col = QColor(); col.setHsv(self.hue, self.sat, self.value) ## self.currentColorChanged.emit(col) ## ## self.cWhlBrush1 = QBrush(colWhl) ## self.update() def resizeEvent(self, event): self.setup() # re-construct the sizes self.setNamedColors(self._namedColorList) def getColor(self): col = QColor() col.setHsv(self.hue, self.sat, self.value) return col def setNamedColors(self, colorList): "sets list [(name, #html)] of named colors" self._namedColorList = colorList lst = [] r2 = (self.vAoBox.width() + self.vAiBox.width()) / 4.0 for i in self._namedColorList: h, s, v, a = QColor(i[1]).getHsv() t = radians(h + self.o_ang * -self.rot_d) * -self.rot_d r = s / 255.0 * self.cW_rad x, y = r * cos(t) + self.cen.x(), r * -sin(t) + self.cen.y() lst.append(QPointF(x, y)) #t2 = ((v / 255.0) * self.ang_w + radians(self.e_ang) + 2 * pi) % (2 * pi) #x, y = r2 * cos(t2) + self.cen.x(), r2 * -sin(t2) + self.cen.y() #lst.append(QPointF(x, y)) self._namedColorPts = lst def showNamedColors(self, flag=False): "show/hide location of named colors on color wheel" self._showNames = flag self.update() def setColor(self, color): # saturation -> radius h, s, v, a = color.getHsv() # hue -> angle self.hue, self.sat, self.value = h, s, v # value -> side bar thingy t = radians(h + self.o_ang * -self.rot_d) * -self.rot_d r = s / 255.0 * self.cW_rad x, y = r * cos(t) + self.cen.x(), r * -sin(t) + self.cen.y() self.chPt = QPointF(x, y) # hue, saturation self.vIdAng = t2 = (v / 255.0) * self.ang_w + radians(self.e_ang) self.vIdAng = t2 = t2 if t2 > 0 else t2 + 2 * pi r2 = self.vAoBox.width() / 2.0 x, y = r2 * cos(t2) + self.cen.x(), r2 * -sin(t2) + self.cen.y() self.vIdCen, self.vIdAng = QPointF(x, y), t2 # value self.vIdBox.moveCenter(self.vIdCen) self.update() def eventFilter(self, source, event): if (event.type() == QEvent.MouseButtonPress or (event.type() == QEvent.MouseMove and event.buttons() == Qt.LeftButton)): self.pos = pos = event.pos() t = atan2(self.cen.y() - pos.y(), pos.x() - self.cen.x()) if self.colWhlPath.contains(pos): # in the color wheel self.chPt = pos #if not self._startedTimer: # self.timer = QTimer() # self.timer.timeout.connect(self.timerSpinner) # self.timer.start(30.303) # self._startedTimer = True # hue -> mouse angle (same as t here) h = (int(degrees(t)) - self.o_ang) * -self.rot_d self.hue = (h if h > 0 else h + 360) % 360 # saturation -> mouse radius (clipped to wheel radius) m_rad = sqrt((self.pos.x() - self.cen.x())**2 + (self.pos.y() - self.cen.y())**2) self.sat = int(255 * min(m_rad / self.cW_rad, 1)) if self.vInArcPath.contains(pos): # in the value selection arc self.vIdAng = t if t > 0 else t + 2 * pi r2 = self.vAoBox.width() / 2.0 x, y = r2 * cos(t) + self.cen.x(), r2 * -sin(t) + self.cen.y() self.vIdCen = QPointF(x, y) self.vIdBox.moveCenter(self.vIdCen) self.value = int(255 * (t - radians(self.e_ang)) / self.ang_w) % 256 self.update() col = QColor() col.setHsv(self.hue, self.sat, self.value) self.currentColorChanged.emit(col) return QWidget.eventFilter(self, source, event) def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(painter.Antialiasing) #painter.setBrush(QBrush(Qt.black, Qt.NoBrush)) #painter.drawRect(self.winBox) # border # value selector indicator painter.setBrush(QBrush(Qt.black, Qt.SolidPattern)) painter.drawPie(self.vIdBox, 16 * (degrees(self.vIdAng) - 22.5), 720) # value selector arc painter.setClipPath(self.vArcPath) painter.setPen(Qt.NoPen) arc = QConicalGradient(self.cen, self.e_ang) color = QColor() color.setHsv(self.hue, self.sat, 255) arc.setColorAt(1 - (self.e_ang - self.s_ang) / 360.0, color) arc.setColorAt(1, Qt.black) arc.setColorAt(0, Qt.black) painter.setBrush(arc) painter.drawPath(self.vArcPath) painter.setClipPath(self.vArcPath, Qt.NoClip) # color wheel painter.setPen(Qt.NoPen) painter.setBrush(self.cWhlBrush1) painter.drawEllipse(self.cWhBox) painter.setBrush(self.cWhlBrush2) painter.drawEllipse(self.cWhBox) # crosshairs painter.setClipPath(self.colWhlPath) painter.setBrush(QBrush(Qt.black, Qt.SolidPattern)) chVert = QRectF(0, 0, 2, 20) chHort = QRectF(0, 0, 20, 2) chVert.moveCenter(self.chPt) chHort.moveCenter(self.chPt) painter.drawRect(chVert) painter.drawRect(chHort) # named color locations if self._showNames: painter.setClipPath(self.vArcPath, Qt.NoClip) painter.setPen(Qt.SolidLine) try: painter.drawPoints(*self._namedColorPts) # PyQt except: painter.drawPoints(self._namedColorPts) # PySide def setup(self): "sets bounds on value arc and color wheel" # bounding boxes self.winBox = QRectF(self.rect()) self.vIoBox = QRectF() # value indicator arc outer self.vIdBox = QRectF() # value indicator box self.vAoBox = QRectF() # value arc outer self.vAiBox = QRectF() # value arc inner self.cWhBox = QRectF() # color wheel self.vIdBox.setSize(QSizeF(15, 15)) self.vIoBox.setSize(self.winBox.size()) self.vAoBox.setSize(self.winBox.size() - self.vIdBox.size() / 2.0) self.vAiBox.setSize(self.vAoBox.size() - QSizeF(20, 20)) self.cWhBox.setSize(self.vAiBox.size() - QSizeF(20, 20)) # center - shifted to the right slightly x = self.winBox.width() - (self.vIdBox.width() + self.vAiBox.width()) / 2.0 self.cen = QPointF(x, self.winBox.height() / 2.0) # positions and initial settings self.vAoBox.moveCenter(self.cen) self.vAiBox.moveCenter(self.cen) self.cWhBox.moveCenter(self.cen) self.vIdBox.moveCenter(self.vIdCen) self.cW_rad = self.cWhBox.width() / 2.0 self.ang_w = radians(self.s_ang) - radians(self.e_ang) # gradients colWhl = QConicalGradient(self.cen, self.o_ang) whl_cols = [ Qt.red, Qt.magenta, Qt.blue, Qt.cyan, Qt.green, Qt.yellow, Qt.red ] for i, c in enumerate(whl_cols[::self.rot_d]): colWhl.setColorAt(i / 6.0, c) rad = min(self.cWhBox.width() / 2.0, self.cWhBox.height() / 2.0) cWhlFade = QRadialGradient(self.cen, rad, self.cen) cWhlFade.setColorAt(0, Qt.white) cWhlFade.setColorAt(1, QColor(255, 255, 255, 0)) self.cWhlBrush1 = QBrush(colWhl) self.cWhlBrush2 = QBrush(cWhlFade) # painter paths (arcs, wheel) rad = self.vAoBox.width() / 2.0 x, y = rad * cos(radians(self.s_ang)), -rad * sin(radians(self.s_ang)) x += self.cen.x() y += self.cen.y() self.vArcPath = QPainterPath(QPointF(x, y)) # value arc (for color) self.vArcPath.arcTo(self.vAoBox, self.s_ang, self.e_ang - self.s_ang) self.vArcPath.arcTo(self.vAiBox, self.e_ang, self.s_ang - self.e_ang) self.vArcPath.closeSubpath() self.vInArcPath = QPainterPath(QPointF(x, y)) # value arc (for mouse) self.vInArcPath.arcTo(self.vIoBox, self.s_ang, self.e_ang - self.s_ang) self.vInArcPath.arcTo(self.vAiBox, self.e_ang, self.s_ang - self.e_ang) self.vInArcPath.closeSubpath() self.colWhlPath = QPainterPath() self.colWhlPath.addEllipse(self.cWhBox)
def draw(self, painter: QPainter, block_length: int): self.pixel_length = block_length / Block.WIDTH self.scroll_brush = QBrush(Qt.blue) self.scroll_pen = QPen(self.scroll_brush, 2 * self.pixel_length) self.acceleration_brush = QBrush(Qt.red) self.acceleration_pen = QPen(self.acceleration_brush, 2 * self.pixel_length) painter.setPen(self.scroll_pen) painter.setBrush(self.scroll_brush) auto_scroll_type_index = self.auto_scroll_row >> 4 auto_scroll_routine_index = self.auto_scroll_row & 0b0001_1111 if auto_scroll_type_index in [ SPIKE_CEILING_SCROLL, UP_TIL_DOOR_SCROLL, WATER_LEVEL_SCROLL, UP_RIGHT_DIAG_SCROLL, ]: # not visualized return elif auto_scroll_type_index not in [ HORIZONTAL_SCROLL_0, HORIZONTAL_SCROLL_1 ]: # illegal value, those appear in the vanilla ROM, though; so error out return first_movement_command_index = (self.rom.int( AScroll_HorizontalInitMove + auto_scroll_routine_index) + 1) % 256 last_movement_command_index = (self.rom.int( AScroll_HorizontalInitMove + auto_scroll_routine_index + 1)) % 256 self.horizontal_speed = 0 self.vertical_speed = 0 self.current_pos = self._determine_auto_scroll_start(block_length) for movement_command_index in range(first_movement_command_index, last_movement_command_index + 1): movement_command = self.rom.int(AScroll_Movement + movement_command_index) movement_repeat = self.rom.int(AScroll_MovementRepeat + movement_command_index) self._execute_movement_command(painter, movement_command, movement_repeat) stop_marker = QRectF(QPoint(0, 0), QSizeF(10, 10) * self.pixel_length) stop_marker.moveCenter(self.current_pos) painter.setPen(Qt.NoPen) painter.drawRect(stop_marker) painter.setPen(self.scroll_pen) painter.setBrush(self.scroll_brush) painter.setOpacity(0.2) painter.drawPolygon(self.screen_polygon)