def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) center = QPointF(self.width() / 2, self.height() / 2) radius = self.radius() ellipse_line_width = self.radius() * 60 / 512 # big ellipse pen = QPen() pen.setWidth(ellipse_line_width) pen.setColor(self.color) painter.setPen(pen) painter.drawEllipse(center, radius - pen.width() / 2, radius - pen.width() / 2) # dots pen = QPen() pen.setColor(QColor(0, 0, 0, 0)) painter.setPen(pen) brush = QBrush() brush.setStyle(Qt.SolidPattern) dot_size = radius * 200 / 1024 color = copy.copy(self.color) self._change_color(painter, brush, color, 0) painter.drawEllipse( QPointF((self.width() - radius - ellipse_line_width / 2) / 2, self.height() / 2), dot_size, dot_size) self._change_color(painter, brush, color, 15) painter.drawEllipse(center, dot_size, dot_size) self._change_color(painter, brush, color, 30) painter.drawEllipse( QPointF((self.width() + radius + ellipse_line_width / 2) / 2, self.height() / 2), dot_size, dot_size)
def particle_pen(self, index: int): pen = QPen() colors = self.settings.list_value(default_settings.particle_color) colors = [QColor(c) for c in colors] pen.setColor(colors[index % len(colors)]) pen.setStyle(Qt.SolidLine) pen.setWidth(0) return pen
def trajectory_pen(self, index: int): if self.settings.boolean_value( default_settings.same_trajectory_color_with_particle): return self.particle_pen(index) else: pen = QPen() colors = self.settings.list_value( default_settings.trajectory_color) colors = [QColor(c) for c in colors] pen.setStyle(Qt.SolidLine) pen.setColor(colors[index % len(colors)]) pen.setWidth( self.settings.int_value(default_settings.trajectory_size)) pen.setJoinStyle(Qt.RoundJoin) pen.setCapStyle(Qt.RoundCap) return pen
def __init__(self, sug=None): super().__init__() p = QPen() p.setColor(QColor("red")) self.addLine(-5, 0, 5, 0, p) self.addLine(0, -5, 0, 5, p) self.sug = sug if self.sug: from grandalf.routing import route_with_lines self.sug.route_edge = route_with_lines self.sug.dx, self.sug.dy = 5, 5 self.sug.dirvh = 0 for n in self.sug.g.sV: self.connect_add(n.view) for e in self.sug.g.sE: e.view = Edge_basic(e.v[0].view.obj, e.v[1].view.obj) self.addItem(e.view)
class HexAreaWidget(QWidget): ''' Responsible for painting the area that actually containts the hex display ''' signal_resized = Signal() signal_scroll_wheel_changed = Signal(int) signal_cursor_changed = Signal(int) signal_selection_updated = Signal(int) signal_key_cursor_pressed = Signal(KeyType) signal_key_selection_pressed = Signal(KeyType) signal_context_menu_shown = Signal(QPoint) signal_show_tooltip_at_offset = Signal(int, QPoint) signal_go_to_pointer_at_offset = Signal(int) def __init__(self, parent: QWidget): # , scroll_bar: QScrollBar, statusBar: QLabel super().__init__(parent=parent) self.line_height = 18 self.byte_width = 25 self.bytes_per_line = settings.get_bytes_per_line() self.label_offset_x = 5 self.label_length = 100 self.is_dragging_to_select = False self.display_data: List[DisplayByte] = [] self.display_labels: List[str] = [] # TODO make configurable self.font = QFont('DejaVu Sans Mono, Courier, Monospace', 12) self.label_color = QColor(128, 128, 128) self.byte_color = QColor(210, 210, 210) self.selection_color = QPen(QColor(97, 175, 239)) self.selection_color.setWidth(2) self.annotation_pen = QPen(QColor(0, 0, 0), 2) self.enabled_constraint_pen = QPen(QColor(255, 80, 0), 2) self.disabled_constraint_pen = QPen(QColor(130, 40, 0), 2) # Make this widget focussable on click, so that we can reduce the context of the shortcut, so that multiple shortcuts are possible in the same window self.setFocusPolicy(Qt.FocusPolicy.ClickFocus) def wheelEvent(self, event): # TODO make scroll speed configurable lines_delta = -int( event.angleDelta().y() / self.line_height) * self.bytes_per_line self.signal_scroll_wheel_changed.emit(lines_delta) def resizeEvent(self, event: QResizeEvent) -> None: self.signal_resized.emit() def paintEvent(self, ev): p = QPainter(self) p.setFont(self.font) #p.fillRect(self.rect(), QBrush(Qt.blue)) length = len(self.display_data) # Reduce to the number of lines that are available in the data num_rows = length // self.bytes_per_line if length % self.bytes_per_line > 0: num_rows += 1 for l in range(num_rows): p.setPen(self.label_color) # Draw address label # self.instance.get_local_label(self.start_offset + l * self.bytes_per_line) position_string = self.display_labels[l] p.drawText(QPoint(self.label_offset_x, (l + 1) * self.line_height), position_string) for i in range( 0, min(self.bytes_per_line, length - self.bytes_per_line * l)): #virtual_address = self.start_offset + l*self.bytes_per_line + i p.setPen(self.byte_color) current_byte = self.display_data[i + l * self.bytes_per_line] if current_byte.background is not None: p.setBackground(current_byte.background) p.setBackgroundMode(Qt.OpaqueMode) p.drawText( QPoint(self.label_length + i * self.byte_width, (l + 1) * self.line_height), current_byte.text) p.setBackgroundMode(Qt.TransparentMode) # Draw selection rects if current_byte.is_selected: p.setPen(self.selection_color) p.drawRect( # TODO make these offsets configurable/dependent on font? self.label_length + i * self.byte_width - 3, (l) * self.line_height + 3, self.byte_width, self.line_height) # Draw annotation underlines if len(current_byte.annotations) > 0: y_offset = 0 for annotation in current_byte.annotations: self.annotation_pen.setColor(annotation.color) p.setPen(self.annotation_pen) x = self.label_length + i * self.byte_width y = (l + 1) * self.line_height + y_offset + 2 p.drawLine(x, y, x + self.byte_width, y) y_offset += 2 # Draw constraint pipes if len(current_byte.constraints) > 0: enabled = False for constraint in current_byte.constraints: if constraint.enabled: enabled = True break if enabled: p.setPen(self.enabled_constraint_pen) else: p.setPen(self.disabled_constraint_pen) x = self.label_length + i * self.byte_width - 2 y = (l) * self.line_height + 3 p.drawLine(x, y, x, y + self.line_height) def number_of_lines_on_screen(self): # +1 to draw cutof lines as well return int(self.height() // self.line_height) + 1 def contextMenuEvent(self, event: QContextMenuEvent) -> None: self.signal_context_menu_shown.emit(event.globalPos()) def mousePressEvent(self, event: QMouseEvent) -> None: if event.button() == Qt.LeftButton: # TODO handle click on label, etc offset = self.xy_to_offset(event.x(), event.y()) if offset is not None: ctrl = event.modifiers( ) & Qt.ControlModifier == Qt.ControlModifier shift = event.modifiers( ) & Qt.ShiftModifier == Qt.ShiftModifier if ctrl: # Go to pointer self.signal_go_to_pointer_at_offset.emit(offset) return if shift: # Move selection instead of cursor self.signal_selection_updated.emit(offset) self.is_dragging_to_select = True return self.signal_cursor_changed.emit(offset) self.is_dragging_to_select = True def mouseMoveEvent(self, event: QMouseEvent) -> None: if self.is_dragging_to_select: offset = self.xy_to_offset(event.x(), event.y()) if offset is not None: self.signal_selection_updated.emit(offset) def mouseReleaseEvent(self, event: QMouseEvent) -> None: self.is_dragging_to_select = False def xy_to_offset(self, x, y) -> Optional[int]: ''' Returns offsets in bytes from the start_offset or None if not clicked on a byte ''' line = y // self.line_height start = self.label_offset_x + self.label_length if x < start or x > start + self.bytes_per_line * self.byte_width: return None col = (x - start) // (self.byte_width) return line * self.bytes_per_line + col def keyPressEvent(self, event: QKeyEvent) -> None: shift = event.modifiers() & Qt.ShiftModifier == Qt.ShiftModifier key = event.key() if key == Qt.Key_Up: if shift: self.signal_key_selection_pressed.emit(KeyType.UP) else: self.signal_key_cursor_pressed.emit(KeyType.UP) elif key == Qt.Key_Down: if shift: self.signal_key_selection_pressed.emit(KeyType.DOWN) else: self.signal_key_cursor_pressed.emit(KeyType.DOWN) elif key == Qt.Key_Left: if shift: self.signal_key_selection_pressed.emit(KeyType.LEFT) else: self.signal_key_cursor_pressed.emit(KeyType.LEFT) elif key == Qt.Key_Right: if shift: self.signal_key_selection_pressed.emit(KeyType.RIGHT) else: self.signal_key_cursor_pressed.emit(KeyType.RIGHT) elif key == Qt.Key_PageUp: if shift: self.signal_key_selection_pressed.emit(KeyType.PAGE_UP) else: self.signal_key_cursor_pressed.emit(KeyType.PAGE_UP) elif key == Qt.Key_PageDown: if shift: self.signal_key_selection_pressed.emit(KeyType.PAGE_DOWN) else: self.signal_key_cursor_pressed.emit(KeyType.PAGE_DOWN) elif key == Qt.Key_Home: if shift: self.signal_key_selection_pressed.emit(KeyType.HOME) else: self.signal_key_cursor_pressed.emit(KeyType.HOME) elif key == Qt.Key_End: if shift: self.signal_key_selection_pressed.emit(KeyType.END) else: self.signal_key_cursor_pressed.emit(KeyType.END) def event(self, event: QEvent) -> bool: if event.type() == QEvent.ToolTip: offset = self.xy_to_offset(event.pos().x(), event.pos().y()) if offset is None: QToolTip.hideText() return True self.signal_show_tooltip_at_offset.emit(offset, event.globalPos()) return True return super().event(event)