def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area """ make_flag = self.make_flag_qrect make_slider = self.make_slider_range # Filling the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) block = self.editor.document().firstBlock() # Painting warnings and todos for line_number in range(1, self.editor.document().blockCount()+1): data = block.userData() if data: position = self.value_to_position(line_number) if data.code_analysis: # Warnings color = self.editor.warning_color for _message, error in data.code_analysis: if error: color = self.editor.error_color break self.set_painter(painter, color) painter.drawRect(make_flag(position)) if data.todo: # TODOs self.set_painter(painter, self.editor.todo_color) painter.drawRect(make_flag(position)) if data.breakpoint: # Breakpoints self.set_painter(painter, self.editor.breakpoint_color) painter.drawRect(make_flag(position)) block = block.next() # Occurrences if self.editor.occurrences: self.set_painter(painter, self.editor.occurrence_color) for line_number in self.editor.occurrences: position = self.value_to_position(line_number) painter.drawRect(make_flag(position)) # Found results if self.editor.found_results: self.set_painter(painter, self.editor.found_results_color) for line_number in self.editor.found_results: position = self.value_to_position(line_number) painter.drawRect(make_flag(position)) # Painting the slider range pen_color = QColor(Qt.white) pen_color.setAlphaF(.8) painter.setPen(pen_color) brush_color = QColor(Qt.white) brush_color.setAlphaF(.5) painter.setBrush(QBrush(brush_color)) painter.drawRect(make_slider(self.editor.firstVisibleBlock().blockNumber()))
class PyDMBitIndicator(QWidget): """ A QWidget which draws a colored circle or rectangle Parameters ---------- parent : QWidget The parent widget for the Label """ def __init__(self, parent=None, circle=False): super(PyDMBitIndicator, self).__init__(parent) self.setAutoFillBackground(True) self.circle = circle self._painter = QPainter() self._brush = QBrush(Qt.SolidPattern) self._pen = QPen(Qt.SolidLine) def paintEvent(self, event): """ Paint events are sent to widgets that need to update themselves, for instance when part of a widget is exposed because a covering widget was moved. Parameters ---------- event : QPaintEvent """ self._painter.begin(self) opt = QStyleOption() opt.initFrom(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, self._painter, self) self._painter.setRenderHint(QPainter.Antialiasing) self._painter.setBrush(self._brush) self._painter.setPen(self._pen) if self.circle: rect = event.rect() w = rect.width() h = rect.height() r = min(w, h) / 2.0 - 2.0 * max(self._pen.widthF(), 1.0) self._painter.drawEllipse(QPoint(w / 2.0, h / 2.0), r, r) else: self._painter.drawRect(event.rect()) self._painter.end() def setColor(self, color): """ Property for the color to be used when drawing Parameters ---------- QColor """ self._brush.setColor(color) self.update() def minimumSizeHint(self): fm = QFontMetrics(self.font()) return QSize(fm.height(), fm.height())
def paintEvent(self, event): QPushButton.paintEvent(self, event) color = self.color() padding = self.padding() rect = event.rect() painter = QPainter() painter.begin(self) painter.setBrush(QBrush(color)) painter.setPen(Qt.NoPen) rect.adjust(padding, padding, -1 - padding, -1 - padding) painter.drawRect(rect) painter.end()
class QScale(QFrame): """ A bar-shaped indicator for scalar value. Configurable features include indicator type (bar/pointer), scale tick marks and orientation (horizontal/vertical). Parameters ---------- parent : QWidget The parent widget for the Scale """ def __init__(self, parent=None): super(QScale, self).__init__(parent) self._value = 1 self._lower_limit = -5 self._upper_limit = 5 self.position = None # unit: pixel self._bg_color = QColor('darkgray') self._bg_size_rate = 0.8 # from 0 to 1 self._indicator_color = QColor('black') self._pointer_width_rate = 0.05 self._barIndicator = False self._num_divisions = 10 self._show_ticks = True self._tick_pen = QPen() self._tick_color = QColor('black') self._tick_width = 0 self._tick_size_rate = 0.1 # from 0 to 1 self._painter = QPainter() self._painter_rotation = None self._painter_translation_y = None self._painter_translation_x = None self._painter_scale_x = None self._flip_traslation_y = None self._flip_scale_y = None self._widget_width = self.width() self._widget_height = self.height() self._orientation = Qt.Horizontal self._inverted_appearance = False self._flip_scale = False self._scale_height = 35 self._origin_at_zero = False self._origin_position = 0 self.set_position() def adjust_transformation(self): """ This method sets parameters for the widget transformations (needed to for orientation, flipping and appearance inversion). """ self.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) # Unset fixed size if self._orientation == Qt.Horizontal: self._widget_width = self.width() self._widget_height = self.height() self._painter_translation_y = 0 self._painter_rotation = 0 self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.setFixedHeight(self._scale_height) elif self._orientation == Qt.Vertical: # Invert dimensions for paintEvent() self._widget_width = self.height() self._widget_height = self.width() self._painter_translation_y = self._widget_width self._painter_rotation = -90 self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.setFixedWidth(self._scale_height) if self._inverted_appearance: self._painter_translation_x = self._widget_width self._painter_scale_x = -1 else: self._painter_translation_x = 0 self._painter_scale_x = 1 if self._flip_scale: self._flip_traslation_y = self._widget_height self._flip_scale_y = -1 else: self._flip_traslation_y = 0 self._flip_scale_y = 1 def set_tick_pen(self): """ Define pen style for drawing scale tick marks. """ self._tick_pen.setColor(self._tick_color) self._tick_pen.setWidth(self._tick_width) def draw_ticks(self): """ Draw tick marks on the scale. """ if not self._show_ticks: return self.set_tick_pen() self._painter.setPen(self._tick_pen) division_size = self._widget_width / self._num_divisions tick_y0 = self._widget_height tick_yf = (1 - self._tick_size_rate)*self._widget_height for i in range(self._num_divisions+1): x = i*division_size self._painter.drawLine(x, tick_y0, x, tick_yf) # x1, y1, x2, y2 def draw_bar(self): """ Draw a bar as indicator of current value. """ self.set_origin() self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) bar_width = self.position - self._origin_position bar_height = self._bg_size_rate * self._widget_height self._painter.drawRect(self._origin_position, 0, bar_width, bar_height) def draw_pointer(self): """ Draw a pointer as indicator of current value. """ self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) pointer_width = self._pointer_width_rate * self._widget_width pointer_height = self._bg_size_rate * self._widget_height points = [ QPoint(self.position, 0), QPoint(self.position + 0.5*pointer_width, 0.5*pointer_height), QPoint(self.position, pointer_height), QPoint(self.position - 0.5*pointer_width, 0.5*pointer_height) ] self._painter.drawPolygon(QPolygon(points)) def draw_indicator(self): """ Draw the selected indicator for current value. """ if self._barIndicator: self.draw_bar() else: self.draw_pointer() def draw_background(self): """ Draw the background of the scale. """ self._painter.setPen(Qt.transparent) self._painter.setBrush(self._bg_color) bg_width = self._widget_width bg_height = self._bg_size_rate * self._widget_height self._painter.drawRect(0, 0, bg_width, bg_height) def paintEvent(self, event): """ Paint events are sent to widgets that need to update themselves, for instance when part of a widget is exposed because a covering widget was moved. Parameters ---------- event : QPaintEvent """ self.adjust_transformation() self._painter.begin(self) self._painter.translate(0, self._painter_translation_y) # Draw vertically if needed self._painter.rotate(self._painter_rotation) self._painter.translate(self._painter_translation_x, 0) # Invert appearance if needed self._painter.scale(self._painter_scale_x, 1) self._painter.translate(0, self._flip_traslation_y) # Invert scale if needed self._painter.scale(1, self._flip_scale_y) self._painter.setRenderHint(QPainter.Antialiasing) self.draw_background() self.draw_ticks() self.draw_indicator() self._painter.end() def calculate_position_for_value(self, value): """ Calculate the position (pixel) in which the pointer should be drawn for a given value. """ if value < self._lower_limit or value > self._upper_limit or \ self._upper_limit - self._lower_limit == 0: proportion = -1 # Invalid else: proportion = (value - self._lower_limit) / (self._upper_limit - self._lower_limit) position = int(proportion * self._widget_width) return position def set_origin(self): """ Set the position (pixel) in which the origin should be drawn. """ if self._origin_at_zero: self._origin_position = self.calculate_position_for_value(0) else: self._origin_position = 0 def set_position(self): """ Set the position (pixel) in which the pointer should be drawn. """ self.position = self.calculate_position_for_value(self._value) def update_indicator(self): """ Update the position and the drawing of indicator. """ self.set_position() self.repaint() def set_value(self, value): """ Set a new current value for the indicator. """ self._value = value self.update_indicator() def set_upper_limit(self, new_limit): """ Set the scale upper limit. Parameters ---------- new_limit : float The upper limit of the scale. """ self._upper_limit = new_limit def set_lower_limit(self, new_limit): """ Set the scale lower limit. Parameters ---------- new_limit : float The lower limit of the scale. """ self._lower_limit = new_limit def get_show_ticks(self): return self._show_ticks def set_show_ticks(self, checked): if self._show_ticks != bool(checked): self._show_ticks = checked self.repaint() def get_orientation(self): return self._orientation def set_orientation(self, orientation): self._orientation = orientation self.adjust_transformation() self.repaint() def get_flip_scale(self): return self._flip_scale def set_flip_scale(self, checked): self._flip_scale = bool(checked) self.adjust_transformation() self.repaint() def get_inverted_appearance(self): return self._inverted_appearance def set_inverted_appearance(self, inverted): self._inverted_appearance = inverted self.adjust_transformation() self.repaint() def get_bar_indicator(self): return self._barIndicator def set_bar_indicator(self, checked): if self._barIndicator != bool(checked): self._barIndicator = checked self.repaint() def get_background_color(self): return self._bg_color def set_background_color(self, color): self._bg_color = color self.repaint() def get_indicator_color(self): return self._indicator_color def set_indicator_color(self, color): self._indicator_color = color self.repaint() def get_tick_color(self): return self._tick_color def set_tick_color(self, color): self._tick_color = color self.repaint() def get_background_size_rate(self): return self._bg_size_rate def set_background_size_rate(self, rate): if rate >= 0 and rate <=1 and self._bg_size_rate != rate: self._bg_size_rate = rate self.repaint() def get_tick_size_rate(self): return self._tick_size_rate def set_tick_size_rate(self, rate): if rate >= 0 and rate <=1 and self._tick_size_rate != rate: self._tick_size_rate = rate self.repaint() def get_num_divisions(self): return self._num_divisions def set_num_divisions(self, divisions): if isinstance(divisions, int) and divisions > 0 and self._num_divisions != divisions: self._num_divisions = divisions self.repaint() def get_scale_height(self): return self._scale_height def set_scale_height(self, value): self._scale_height = int(value) self.adjust_transformation() self.repaint() def get_origin_at_zero(self): return self._origin_at_zero def set_origin_at_zero(self, checked): if self._origin_at_zero != bool(checked): self._origin_at_zero = checked self.repaint()
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area """ make_flag = self.make_flag_qrect # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # Paint warnings and todos block = self.editor.document().firstBlock() for line_number in range(self.editor.document().blockCount() + 1): data = block.userData() if data: if data.code_analysis: # Paint the warnings color = self.editor.warning_color for source, code, severity, message in data.code_analysis: error = severity == DiagnosticSeverity.ERROR if error: color = self.editor.error_color break self.set_painter(painter, color) painter.drawRect(make_flag(line_number)) if data.todo: # Paint the todos self.set_painter(painter, self.editor.todo_color) painter.drawRect(make_flag(line_number)) if data.breakpoint: # Paint the breakpoints self.set_painter(painter, self.editor.breakpoint_color) painter.drawRect(make_flag(line_number)) block = block.next() # Paint the occurrences if self.editor.occurrences: self.set_painter(painter, self.editor.occurrence_color) for line_number in self.editor.occurrences: painter.drawRect(make_flag(line_number)) # Paint the found results if self.editor.found_results: self.set_painter(painter, self.editor.found_results_color) for line_number in self.editor.found_results: painter.drawRect(make_flag(line_number)) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = self.editor.rect().contains( self.editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if ((is_over_self or (alt and is_over_editor)) and self.slider): pen_color = QColor(Qt.gray) pen_color.setAlphaF(.85) painter.setPen(pen_color) brush_color = QColor(Qt.gray) brush_color.setAlphaF(.5) painter.setBrush(QBrush(brush_color)) painter.drawRect(self.make_slider_range(cursor_pos)) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False
class BaseCanvas(QWidget, metaclass=QABCMeta): """The subclass can draw a blank canvas more easier.""" ranges: Dict[str, QRectF] target_path: Dict[int, Sequence[_Coord]] @abstractmethod def __init__(self, parent: QWidget): """Set the parameters for drawing.""" super(BaseCanvas, self).__init__(parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setFocusPolicy(Qt.StrongFocus) self.setMouseTracking(True) self.painter = QPainter() # Origin coordinate self.ox = self.width() / 2 self.oy = self.height() / 2 # Canvas zoom rate self.zoom = 1. # Joint size self.joint_size = 5 # Canvas line width self.link_width = 3 self.path_width = 3 # Font size self.font_size = 15 # Show point mark or dimension self.show_ticks = _TickMark.SHOW self.show_point_mark = True self.show_dimension = True # Path track self.path = _PathOption() # Path solving self.ranges = {} self.target_path = {} self.show_target_path = False # Background self.background = QImage() self.background_opacity = 1. self.background_scale = 1. self.background_offset = QPointF(0, 0) # Monochrome mode self.monochrome = False # Grab mode self.__grab_mode = False def switch_grab(self) -> None: """Start grab mode.""" self.__grab_mode = not self.__grab_mode @staticmethod def zoom_factor(width: int, height: int, x_right: float, x_left: float, y_top: float, y_bottom: float) -> float: """Calculate the zoom factor.""" x_diff = x_left - x_right y_diff = y_top - y_bottom x_diff = x_diff if x_diff else 1. y_diff = y_diff if y_diff else 1. if width / x_diff < height / y_diff: return width / x_diff else: return height / y_diff @abstractmethod def paintEvent(self, event: QPaintEvent) -> None: """Using a QPainter under 'self', so just change QPen or QBrush before painting. """ if not self.__grab_mode: self.painter.begin(self) self.painter.fillRect(event.rect(), QBrush(Qt.white)) # Translation self.painter.translate(self.ox, self.oy) # Background if not self.background.isNull(): rect = self.background.rect() self.painter.setOpacity(self.background_opacity) self.painter.drawImage( QRectF( self.background_offset * self.zoom, QSizeF(rect.width(), rect.height()) * self.background_scale * self.zoom), self.background, QRectF(rect)) self.painter.setOpacity(1) # Show frame pen = QPen(Qt.blue) pen.setWidth(1) self.painter.setPen(pen) self.painter.setFont(QFont("Arial", self.font_size)) # Draw origin lines if self.show_ticks not in {_TickMark.SHOW, _TickMark.SHOW_NUM}: return pen.setColor(Qt.gray) self.painter.setPen(pen) x_l = -self.ox x_r = self.width() - self.ox self.painter.drawLine(x_l, 0, x_r, 0) y_t = self.height() - self.oy y_b = -self.oy self.painter.drawLine(0, y_b, 0, y_t) def indexing(v: float) -> int: """Draw tick.""" return int(v / self.zoom - v / self.zoom % 5) # Draw tick for x in range(indexing(x_l), indexing(x_r) + 1, 5): if x == 0: continue is_ten = x % 10 == 0 end = QPointF(x * self.zoom, -10 if is_ten else -5) self.painter.drawLine(QPointF(x, 0) * self.zoom, end) if self.show_ticks == _TickMark.SHOW_NUM and is_ten: self.painter.drawText(end + QPointF(0, 3), f"{x}") for y in range(indexing(y_b), indexing(y_t) + 1, 5): if y == 0: continue is_ten = y % 10 == 0 end = QPointF(10 if is_ten else 5, y * self.zoom) self.painter.drawLine(QPointF(0, y) * self.zoom, end) if self.show_ticks == _TickMark.SHOW_NUM and is_ten: self.painter.drawText(end + QPointF(3, 0), f"{-y}") # Please to call the "end" method when ending paint event. def draw_circle(self, p: QPointF, r: float) -> None: """Draw circle.""" self.painter.drawEllipse(p, r, r) def draw_point(self, i: int, cx: float, cy: float, fixed: bool, color: Optional[Tuple[int, int, int]], mul: int = 1) -> None: """Draw a joint.""" if self.monochrome or color is None: color = Qt.black else: color = QColor(*color) pen = QPen(color) pen.setWidth(2) self.painter.setPen(pen) x = cx * self.zoom y = cy * -self.zoom if fixed: # Draw a triangle below self.painter.drawPolygon( QPointF(x, y), QPointF(x - self.joint_size, y + 2 * self.joint_size), QPointF(x + self.joint_size, y + 2 * self.joint_size)) r = self.joint_size for _ in range(1 if mul < 1 else mul): self.draw_circle(QPointF(x, y), r) r += 5 if not self.show_point_mark: return pen.setColor(Qt.darkGray) pen.setWidth(2) self.painter.setPen(pen) text = f"[Point{i}]" if self.show_dimension: text += f":({cx:.02f}, {cy:.02f})" self.painter.drawText(QPointF(x, y) + QPointF(6, -6), text) def draw_ranges(self) -> None: """Draw rectangle ranges.""" pen = QPen() pen.setWidth(5) for i, (tag, rect) in enumerate(self.ranges.items()): range_color = QColor(color_num(i + 1)) range_color.setAlpha(30) self.painter.setBrush(range_color) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) cx = rect.x() * self.zoom cy = rect.y() * -self.zoom if rect.width(): self.painter.drawRect( QRectF(QPointF(cx, cy), QSizeF(rect.width(), rect.height()) * self.zoom)) else: self.draw_circle(QPointF(cx, cy), 3) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) self.painter.drawText(QPointF(cx, cy) + QPointF(6, -6), tag) self.painter.setBrush(Qt.NoBrush) def draw_target_path(self) -> None: """Draw solving path.""" pen = QPen() pen.setWidth(self.path_width) for i, n in enumerate(sorted(self.target_path)): path = self.target_path[n] if self.monochrome: line, dot = target_path_style(0) else: line, dot = target_path_style(i + 1) pen.setColor(line) self.painter.setPen(pen) if len(path) == 1: x, y = path[0] p = QPointF(x, -y) * self.zoom self.painter.drawText(p + QPointF(6, -6), f"P{n}") pen.setColor(dot) self.painter.setPen(pen) self.draw_circle(p, self.joint_size) else: painter_path = QPainterPath() for j, (x, y) in enumerate(path): p = QPointF(x, -y) * self.zoom self.draw_circle(p, self.joint_size) if j == 0: self.painter.drawText(p + QPointF(6, -6), f"P{n}") painter_path.moveTo(p) else: xb, yb = path[j - 1] self.draw_arrow(xb, yb, x, y, line=False) painter_path.lineTo(p) pen.setColor(line) self.painter.setPen(pen) self.painter.drawPath(painter_path) for x, y in path: pen.setColor(dot) self.painter.setPen(pen) self.draw_circle( QPointF(x, -y) * self.zoom, self.joint_size) self.painter.setBrush(Qt.NoBrush) def draw_arrow(self, x1: float, y1: float, x2: float, y2: float, *, zoom: bool = True, line: bool = True, text: str = '') -> None: """Base point -> Vector point""" if zoom: x1 *= self.zoom y1 *= self.zoom x2 *= self.zoom y2 *= self.zoom a = atan2(y1 - y2, x1 - x2) x2 = (x1 + x2) / 2 - 7.5 * cos(a) y2 = (y1 + y2) / 2 - 7.5 * sin(a) first_point = QPointF(x2, -y2) if line: self.painter.drawLine(x1, -y1, x2, -y2) self.painter.drawLine( first_point, QPointF(x2 + 15 * cos(a + radians(20)), -y2 - 15 * sin(a + radians(20)))) self.painter.drawLine( first_point, QPointF(x2 + 15 * cos(a - radians(20)), -y2 - 15 * sin(a - radians(20)))) if not text: return # Font font = self.painter.font() font_copy = QFont(font) font.setBold(True) font.setPointSize(font.pointSize() + 8) self.painter.setFont(font) # Color pen = self.painter.pen() color = pen.color() pen.setColor(color.darker()) self.painter.setPen(pen) self.painter.drawText(first_point, text) pen.setColor(color) self.painter.setPen(pen) self.painter.setFont(font_copy) def draw_curve(self, path: Sequence[_Coord]) -> None: """Draw path as curve.""" if len(set(path)) < 2: return painter_path = QPainterPath() error = False for i, (x, y) in enumerate(path): if isnan(x): error = True self.painter.drawPath(painter_path) painter_path = QPainterPath() else: p = QPointF(x, -y) * self.zoom if i == 0: painter_path.moveTo(p) self.draw_circle(p, 2) continue if error: painter_path.moveTo(p) error = False else: painter_path.lineTo(p) self.painter.drawPath(painter_path) def draw_dot(self, path: Sequence[_Coord]) -> None: """Draw path as dots.""" if len(set(path)) < 2: return for i, (x, y) in enumerate(path): if isnan(x): continue p = QPointF(x, -y) * self.zoom if i == 0: self.draw_circle(p, 2) else: self.painter.drawPoint(p) def solution_polygon(self, func: str, args: Sequence[str], target: str, pos: Sequence[VPoint]) -> Tuple[List[_Coord], QColor]: """Get solution polygon.""" params = [args[0]] if func == 'PLLP': color = QColor(121, 171, 252) params.append(args[-1]) elif func == 'PLAP': color = QColor(249, 84, 216) else: if func == 'PLPP': color = QColor(94, 255, 185) else: # PXY color = QColor(249, 175, 27) params.append(target) polygon = [] for name in params: try: index = int(name.replace('P', '')) except ValueError: continue else: vpoint = pos[index] polygon.append((vpoint.cx * self.zoom, -vpoint.cy * self.zoom)) return polygon, color def draw_solution(self, func: str, args: Sequence[str], target: str, pos: Sequence[VPoint]) -> None: """Draw the solution triangle.""" points, color = self.solution_polygon(func, args, target, pos) color.setAlpha(150) pen = QPen(color) pen.setWidth(self.joint_size) self.painter.setPen(pen) def draw_arrow(index: int, text: str) -> None: """Draw arrow.""" x0, y0 = points[index] x1, y1 = points[-1] self.draw_arrow(x0, -y0, x1, -y1, zoom=False, line=False, text=text) draw_arrow(0, args[1]) if func == 'PLLP': draw_arrow(1, args[2]) color.setAlpha(30) self.painter.setBrush(QBrush(color)) self.painter.drawPolygon(QPolygonF([QPointF(x, y) for x, y in points])) self.painter.setBrush(Qt.NoBrush) @Slot(int) def set_show_ticks(self, show: int): """Set the appearance of tick mark.""" self.show_ticks = _TickMark(show + 1) self.update() @Slot(bool) def set_monochrome_mode(self, monochrome: bool) -> None: """Set monochrome mode.""" self.monochrome = monochrome self.update()
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area There is two cases: - The scroll bar is moving, in which case paint all flags. - The scroll bar is not moving, only paint flags corresponding to visible lines. """ # The area in which the slider handle of the scrollbar may move. groove_rect = self.get_scrollbar_groove_rect() # The scrollbar's scale factor ratio between pixel span height and # value span height scale_factor = groove_rect.height() / self.get_scrollbar_value_height() # The vertical offset of the scroll flag area relative to the # top of the text editor. offset = groove_rect.y() # Note that we calculate the pixel metrics required to draw the flags # here instead of using the convenience methods of the ScrollFlagArea # for performance reason. rect_x = ceil(self.FLAGS_DX / 2) rect_w = self.WIDTH - self.FLAGS_DX rect_h = self.FLAGS_DY # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) editor = self.editor # Define compute_flag_ypos to position the flags: # Paint flags for the entire document last_line = editor.document().lastBlock().firstLineNumber() # The 0.5 offset is used to align the flags with the center of # their corresponding text edit block before scaling. first_y_pos = self.value_to_position( 0.5, scale_factor, offset) - self.FLAGS_DY / 2 last_y_pos = self.value_to_position( last_line + 0.5, scale_factor, offset) - self.FLAGS_DY / 2 def compute_flag_ypos(block): line_number = block.firstLineNumber() if editor.verticalScrollBar().maximum() == 0: geometry = editor.blockBoundingGeometry(block) pos = geometry.y() + geometry.height() / 2 + self.FLAGS_DY / 2 elif last_line != 0: frac = line_number / last_line pos = first_y_pos + frac * (last_y_pos - first_y_pos) else: pos = first_y_pos return ceil(pos) # All the lists of block numbers for flags dict_flag_lists = { "occurrence": editor.occurrences, "found_results": editor.found_results } dict_flag_lists.update(self._dict_flag_list) for flag_type in dict_flag_lists: painter.setBrush(self._facecolors[flag_type]) painter.setPen(self._edgecolors[flag_type]) for block_number in dict_flag_lists[flag_type]: # Find the block block = editor.document().findBlockByNumber(block_number) if not block.isValid(): continue # paint if everything else is fine rect_y = compute_flag_ypos(block) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down if self.slider: cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = editor.rect().contains( editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if is_over_self or (alt and is_over_editor): painter.setPen(self._slider_range_color) painter.setBrush(self._slider_range_brush) x, y, width, height = self.make_slider_range( cursor_pos, scale_factor, offset, groove_rect) painter.drawRect(x, y, width, height) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False
class QScale(QFrame): """ A bar-shaped indicator for scalar value. Configurable features include indicator type (bar/pointer), scale tick marks and orientation (horizontal/vertical). Parameters ---------- parent : QWidget The parent widget for the Scale """ def __init__(self, parent=None): super(QScale, self).__init__(parent) self._value = 1 self._lower_limit = -5 self._upper_limit = 5 self.position = None # unit: pixel self._bg_color = QColor('darkgray') self._bg_size_rate = 0.8 # from 0 to 1 self._indicator_color = QColor('black') self._pointer_width_rate = 0.05 self._barIndicator = False self._num_divisions = 10 self._show_ticks = True self._tick_pen = QPen() self._tick_color = QColor('black') self._tick_width = 0 self._tick_size_rate = 0.1 # from 0 to 1 self._painter = QPainter() self._painter_rotation = None self._painter_translation_y = None self._painter_translation_x = None self._painter_scale_x = None self._flip_traslation_y = None self._flip_scale_y = None self._widget_width = self.width() self._widget_height = self.height() self._orientation = Qt.Horizontal self._inverted_appearance = False self._flip_scale = False self._scale_height = 35 self._origin_at_zero = False self._origin_position = 0 self.set_position() def adjust_transformation(self): """ This method sets parameters for the widget transformations (needed to for orientation, flipping and appearance inversion). """ self.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) # Unset fixed size if self._orientation == Qt.Horizontal: self._widget_width = self.width() self._widget_height = self.height() self._painter_translation_y = 0 self._painter_rotation = 0 self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.setFixedHeight(self._scale_height) elif self._orientation == Qt.Vertical: # Invert dimensions for paintEvent() self._widget_width = self.height() self._widget_height = self.width() self._painter_translation_y = self._widget_width self._painter_rotation = -90 self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.setFixedWidth(self._scale_height) if self._inverted_appearance: self._painter_translation_x = self._widget_width self._painter_scale_x = -1 else: self._painter_translation_x = 0 self._painter_scale_x = 1 if self._flip_scale: self._flip_traslation_y = self._widget_height self._flip_scale_y = -1 else: self._flip_traslation_y = 0 self._flip_scale_y = 1 def set_tick_pen(self): """ Define pen style for drawing scale tick marks. """ self._tick_pen.setColor(self._tick_color) self._tick_pen.setWidth(self._tick_width) def draw_ticks(self): """ Draw tick marks on the scale. """ if not self._show_ticks: return self.set_tick_pen() self._painter.setPen(self._tick_pen) division_size = self._widget_width / self._num_divisions tick_y0 = self._widget_height tick_yf = (1 - self._tick_size_rate) * self._widget_height for i in range(self._num_divisions + 1): x = i * division_size self._painter.drawLine(x, tick_y0, x, tick_yf) # x1, y1, x2, y2 def draw_bar(self): """ Draw a bar as indicator of current value. """ self.set_origin() self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) bar_width = self.position - self._origin_position bar_height = self._bg_size_rate * self._widget_height self._painter.drawRect(self._origin_position, 0, bar_width, bar_height) def draw_pointer(self): """ Draw a pointer as indicator of current value. """ self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) pointer_width = self._pointer_width_rate * self._widget_width pointer_height = self._bg_size_rate * self._widget_height points = [ QPoint(self.position, 0), QPoint(self.position + 0.5 * pointer_width, 0.5 * pointer_height), QPoint(self.position, pointer_height), QPoint(self.position - 0.5 * pointer_width, 0.5 * pointer_height) ] self._painter.drawPolygon(QPolygon(points)) def draw_indicator(self): """ Draw the selected indicator for current value. """ if self._barIndicator: self.draw_bar() else: self.draw_pointer() def draw_background(self): """ Draw the background of the scale. """ self._painter.setPen(Qt.transparent) self._painter.setBrush(self._bg_color) bg_width = self._widget_width bg_height = self._bg_size_rate * self._widget_height self._painter.drawRect(0, 0, bg_width, bg_height) def paintEvent(self, event): """ Paint events are sent to widgets that need to update themselves, for instance when part of a widget is exposed because a covering widget was moved. Parameters ---------- event : QPaintEvent """ self.adjust_transformation() self._painter.begin(self) self._painter.translate( 0, self._painter_translation_y) # Draw vertically if needed self._painter.rotate(self._painter_rotation) self._painter.translate(self._painter_translation_x, 0) # Invert appearance if needed self._painter.scale(self._painter_scale_x, 1) self._painter.translate( 0, self._flip_traslation_y) # Invert scale if needed self._painter.scale(1, self._flip_scale_y) self._painter.setRenderHint(QPainter.Antialiasing) self.draw_background() self.draw_ticks() self.draw_indicator() self._painter.end() def calculate_position_for_value(self, value): """ Calculate the position (pixel) in which the pointer should be drawn for a given value. """ if value < self._lower_limit or value > self._upper_limit or \ self._upper_limit - self._lower_limit == 0: proportion = -1 # Invalid else: proportion = (value - self._lower_limit) / (self._upper_limit - self._lower_limit) position = int(proportion * self._widget_width) return position def set_origin(self): """ Set the position (pixel) in which the origin should be drawn. """ if self._origin_at_zero: self._origin_position = self.calculate_position_for_value(0) else: self._origin_position = 0 def set_position(self): """ Set the position (pixel) in which the pointer should be drawn. """ self.position = self.calculate_position_for_value(self._value) def update_indicator(self): """ Update the position and the drawing of indicator. """ self.set_position() self.repaint() def set_value(self, value): """ Set a new current value for the indicator. """ self._value = value self.update_indicator() def set_upper_limit(self, new_limit): """ Set the scale upper limit. Parameters ---------- new_limit : float The upper limit of the scale. """ self._upper_limit = new_limit def set_lower_limit(self, new_limit): """ Set the scale lower limit. Parameters ---------- new_limit : float The lower limit of the scale. """ self._lower_limit = new_limit def get_show_ticks(self): return self._show_ticks def set_show_ticks(self, checked): if self._show_ticks != bool(checked): self._show_ticks = checked self.repaint() def get_orientation(self): return self._orientation def set_orientation(self, orientation): self._orientation = orientation self.adjust_transformation() self.repaint() def get_flip_scale(self): return self._flip_scale def set_flip_scale(self, checked): self._flip_scale = bool(checked) self.adjust_transformation() self.repaint() def get_inverted_appearance(self): return self._inverted_appearance def set_inverted_appearance(self, inverted): self._inverted_appearance = inverted self.adjust_transformation() self.repaint() def get_bar_indicator(self): return self._barIndicator def set_bar_indicator(self, checked): if self._barIndicator != bool(checked): self._barIndicator = checked self.repaint() def get_background_color(self): return self._bg_color def set_background_color(self, color): self._bg_color = color self.repaint() def get_indicator_color(self): return self._indicator_color def set_indicator_color(self, color): self._indicator_color = color self.repaint() def get_tick_color(self): return self._tick_color def set_tick_color(self, color): self._tick_color = color self.repaint() def get_background_size_rate(self): return self._bg_size_rate def set_background_size_rate(self, rate): if rate >= 0 and rate <= 1 and self._bg_size_rate != rate: self._bg_size_rate = rate self.repaint() def get_tick_size_rate(self): return self._tick_size_rate def set_tick_size_rate(self, rate): if rate >= 0 and rate <= 1 and self._tick_size_rate != rate: self._tick_size_rate = rate self.repaint() def get_num_divisions(self): return self._num_divisions def set_num_divisions(self, divisions): if isinstance( divisions, int) and divisions > 0 and self._num_divisions != divisions: self._num_divisions = divisions self.repaint() def get_scale_height(self): return self._scale_height def set_scale_height(self, value): self._scale_height = int(value) self.adjust_transformation() self.repaint() def get_origin_at_zero(self): return self._origin_at_zero def set_origin_at_zero(self, checked): if self._origin_at_zero != bool(checked): self._origin_at_zero = checked self.repaint()
def create_high_dpi_drop_indicator_pixmap( self, size: QSizeF, area: DockWidgetArea, mode: OverlayMode) -> QPixmap: ''' Create high dpi drop indicator pixmap Parameters ---------- size : QSizeF area : DockWidgetArea mode : OverlayMode Returns ------- value : QPixmap ''' border_color = self.icon_color(IconColor.frame_color) background_color = self.icon_color(IconColor.window_background_color) window = self.public.window() # QT version compatibility (TODO necessary for qtpy?) device_pixel_ratio = (window.devicePixelRatioF() if hasattr(window, 'devicePixelRatioF') else window.devicePixelRatio()) pixmap_size = QSizeF(size * device_pixel_ratio) pm = QPixmap(pixmap_size.toSize()) pm.fill(QColor(0, 0, 0, 0)) p = QPainter(pm) pen = p.pen() shadow_rect = QRectF(pm.rect()) base_rect = QRectF() base_rect.setSize(shadow_rect.size() * 0.7) base_rect.moveCenter(shadow_rect.center()) # Fill shadow_color = self.icon_color(IconColor.shadow_color) if shadow_color.alpha() == 255: shadow_color.setAlpha(64) p.fillRect(shadow_rect, shadow_color) # Drop area rect. p.save() area_rect = QRectF() area_line = QLineF() non_area_rect = QRectF() if area == DockWidgetArea.top: area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(), base_rect.height()*.5) non_area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5, base_rect.width(), base_rect.height()*.5) area_line = QLineF(area_rect.bottomLeft(), area_rect.bottomRight()) elif area == DockWidgetArea.right: area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(), base_rect.width()*.5, base_rect.height()) non_area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width()*.5, base_rect.height()) area_line = QLineF(area_rect.topLeft(), area_rect.bottomLeft()) elif area == DockWidgetArea.bottom: area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5, base_rect.width(), base_rect.height()*.5) non_area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(), base_rect.height()*.5) area_line = QLineF(area_rect.topLeft(), area_rect.topRight()) elif area == DockWidgetArea.left: area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width()*.5, base_rect.height()) non_area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(), base_rect.width()*.5, base_rect.height()) area_line = QLineF(area_rect.topRight(), area_rect.bottomRight()) baseSize = base_rect.size() if (OverlayMode.container == mode and area != DockWidgetArea.center): base_rect = area_rect p.fillRect(base_rect, background_color) if area_rect.isValid(): pen = p.pen() pen.setColor(border_color) Color = self.icon_color(IconColor.overlay_color) if Color.alpha() == 255: Color.setAlpha(64) p.setBrush(Color) p.setPen(Qt.NoPen) p.drawRect(area_rect) pen = p.pen() pen.setWidth(1) pen.setColor(border_color) pen.setStyle(Qt.DashLine) p.setPen(pen) p.drawLine(area_line) p.restore() p.save() # Draw outer border pen = p.pen() pen.setColor(border_color) pen.setWidth(1) p.setBrush(Qt.NoBrush) p.setPen(pen) p.drawRect(base_rect) # draw window title bar p.setBrush(border_color) frame_rect = QRectF(base_rect.topLeft(), QSizeF(base_rect.width(), baseSize.height()/10)) p.drawRect(frame_rect) p.restore() # Draw arrow for outer container drop indicators if (OverlayMode.container == mode and area != DockWidgetArea.center): arrow_rect = QRectF() arrow_rect.setSize(baseSize) arrow_rect.setWidth(arrow_rect.width()/4.6) arrow_rect.setHeight(arrow_rect.height()/2) arrow_rect.moveCenter(QPointF(0, 0)) arrow = QPolygonF() arrow.append(arrow_rect.topLeft()) arrow.append(QPointF(arrow_rect.right(), arrow_rect.center().y())) arrow.append(arrow_rect.bottomLeft()) p.setPen(Qt.NoPen) p.setBrush(self.icon_color(IconColor.arrow_color)) p.setRenderHint(QPainter.Antialiasing, True) p.translate(non_area_rect.center().x(), non_area_rect.center().y()) if area == DockWidgetArea.top: p.rotate(-90) elif area == DockWidgetArea.right: ... elif area == DockWidgetArea.bottom: p.rotate(90) elif area == DockWidgetArea.left: p.rotate(180) p.drawPolygon(arrow) pm.setDevicePixelRatio(device_pixel_ratio) return pm
def paintEvent(self, event): painter = QPainter(self) painter.setRenderHints(QPainter.Antialiasing) painter.setPen(Qt.NoPen) if self.hover: painter.setBrush( QColor(self.back_color.red() + 30, self.back_color.green() + 30, self.back_color.blue() + 30)) self.lineEdit.set_back_color( QColor(self.back_color.red() + 30, self.back_color.green() + 30, self.back_color.blue() + 30)) else: painter.setBrush(self.back_color) self.lineEdit.set_back_color(self.back_color) painter.drawRoundedRect(QRect(0, 0, self.width(), self.height()), self.border_radius, self.border_radius) pen = QPen(self.down_arrow_color, self.drop_thick, Qt.SolidLine) painter.setPen(pen) self.down_arrow_poly = QPolygon() x1 = QPoint(self.label_width + float(self.height() / 3), float(self.height() * 0.6)) x2 = QPoint( self.label_width + float(self.height() / 3) + float(self.height() * self.rate / 2), float(self.height() * 0.75)) x3 = QPoint(self.width() - float(self.height() / 3), float(self.height() * 0.6)) self.down_arrow_poly << x1 << x2 << x3 check_path = QPainterPath() check_path.moveTo(x1) check_path.lineTo(x2) check_path.lineTo(x3) check_path.lineTo(x1) painter.drawPath(check_path) if self.down_arrow_color == self.arrow_activate_color: painter.fillPath(check_path, QBrush(self.down_arrow_color)) else: if self.hover: painter.fillPath( check_path, QColor(self.back_color.red() + 30, self.back_color.green() + 30, self.back_color.blue() + 30)) else: painter.fillPath(check_path, QBrush(self.back_color)) pen = QPen(self.up_arrow_color, self.drop_thick, Qt.SolidLine) painter.setPen(pen) x1 = QPoint(self.label_width + float(self.height() / 3), float(self.height() * 0.4)) x2 = QPoint( self.label_width + float(self.height() / 3) + float(self.height() * self.rate / 2), float(self.height() * 0.25)) x3 = QPoint(self.width() - float(self.height() / 3), float(self.height() * 0.4)) self.up_arrow_poly = QPolygon() self.up_arrow_poly << x1 << x2 << x3 check_path = QPainterPath() check_path.moveTo(x1) check_path.lineTo(x2) check_path.lineTo(x3) check_path.lineTo(x1) painter.drawPath(check_path) if self.up_arrow_color == self.arrow_activate_color: painter.fillPath(check_path, QBrush(self.up_arrow_color)) else: if self.hover: painter.fillPath( check_path, QColor(self.back_color.red() + 30, self.back_color.green() + 30, self.back_color.blue() + 30)) else: painter.fillPath(check_path, QBrush(self.back_color))
def graph2icon(g: Graph, width: int, node_mode: bool, show_label: bool, monochrome: bool, *, except_node: Optional[int] = None, engine: str = "", pos: Optional[_Pos] = None) -> QIcon: """Draw a generalized chain graph.""" if engine: pos = engine_picker(g, engine, node_mode) if pos is None: raise ValueError("no engine selected") if not pos: pixmap = QPixmap(width, width) pixmap.fill(Qt.transparent) return QIcon(pixmap) width_bound = -float('inf') for x, y in pos.values(): if abs(x) > width_bound: width_bound = x if abs(y) > width_bound: width_bound = y width_bound *= 2.5 image = QImage(QSize(int(width_bound), int(width_bound)), QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) painter = QPainter(image) painter.translate(image.width() / 2, image.height() / 2) pen = QPen() r = int(width_bound / 50) pen.setWidth(r) painter.setPen(pen) _font.setPixelSize(r * 6) painter.setFont(_font) # Draw edges if node_mode: for l1, l2 in g.edges: if except_node in {l1, l2}: pen.setColor(Qt.gray) else: pen.setColor(Qt.black) painter.setPen(pen) painter.drawLine(QPointF(pos[l1][0], -pos[l1][1]), QPointF(pos[l2][0], -pos[l2][1])) else: if monochrome: color = QColor(Qt.darkGray) else: color = LINK_COLOR color.setAlpha(150) painter.setBrush(QBrush(color)) for link in g.vertices: if link == except_node: pen.setColor(Qt.gray) else: pen.setColor(Qt.black) painter.setPen(pen) painter.drawPolygon(*convex_hull([(pos[n][0], -pos[n][1]) for n, edge in edges_view(g) if link in edge], as_qpoint=True)) # Draw vertices for k, (x, y) in pos.items(): if node_mode: color = color_num(len(list(g.neighbors(k))) - 1) if k == except_node: color.setAlpha(150) else: if monochrome: color = Qt.black elif except_node in dict(edges_view(g))[k]: color = color_qt('Green') else: color = color_qt('Blue') pen.setColor(color) painter.setPen(pen) painter.setBrush(QBrush(color)) point = QPointF(x, -y) painter.drawEllipse(point, r, r) if show_label: pen.setColor(Qt.darkMagenta) painter.setPen(pen) painter.drawText(point, str(k)) painter.end() return QIcon(QPixmap.fromImage(image).scaledToWidth(width))
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area There is two cases: - The scroll bar is moving, in which case paint all flags. - The scroll bar is not moving, only paint flags corresponding to visible lines. """ # The area in which the slider handle of the scrollbar may move. groove_rect = self.get_scrollbar_groove_rect() # The scrollbar's scale factor ratio between pixel span height and # value span height scale_factor = groove_rect.height() / self.get_scrollbar_value_height() # The vertical offset of the scroll flag area relative to the # top of the text editor. offset = groove_rect.y() # Note that we calculate the pixel metrics required to draw the flags # here instead of using the convenience methods of the ScrollFlagArea # for performance reason. rect_x = ceil(self.FLAGS_DX / 2) rect_w = self.WIDTH - self.FLAGS_DX rect_h = self.FLAGS_DY # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) editor = self.editor # Check if the slider is visible paint_local = not bool(self.slider) # Define compute_flag_ypos to position the flags: if not paint_local: # Paint flags for the entire document last_line = editor.document().lastBlock().firstLineNumber() # The 0.5 offset is used to align the flags with the center of # their corresponding text edit block before scaling. first_y_pos = self.value_to_position( 0.5, scale_factor, offset) - self.FLAGS_DY / 2 last_y_pos = self.value_to_position( last_line + 0.5, scale_factor, offset) - self.FLAGS_DY / 2 def compute_flag_ypos(block): line_number = block.firstLineNumber() frac = line_number / last_line pos = first_y_pos + frac * (last_y_pos - first_y_pos) return ceil(pos) else: # Only paint flags for visible lines visible_lines = [val[1] for val in editor.visible_blocks] if not visible_lines: # Nothing to do return min_line = min(visible_lines) max_line = max(visible_lines) def compute_flag_ypos(block): # When the vertical scrollbar is not visible, the flags are # vertically aligned with the center of their corresponding # text block with no scaling. top = editor.blockBoundingGeometry(block).translated( editor.contentOffset()).top() bottom = top + editor.blockBoundingRect(block).height() middle = (top + bottom)/2 return ceil(middle-self.FLAGS_DY/2) def should_paint_block(block): """Check if the block should be painted.""" if not block.isValid(): return False # Don't paint local flags outside of the window if paint_local and not ( min_line <= block.blockNumber() + 1 <= max_line): return False return True # Paint all the code analysis flags for block, data in self._code_analysis_list: if not should_paint_block(block): continue # Paint the warnings for source, code, severity, message in data.code_analysis: error = severity == DiagnosticSeverity.ERROR if error: painter.setBrush(self._facecolors['error']) painter.setPen(self._edgecolors['error']) break else: painter.setBrush(self._facecolors['warning']) painter.setPen(self._edgecolors['warning']) rect_y = compute_flag_ypos(block) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint all the todo flags for block, data in self._todo_list: if not should_paint_block(block): continue # Paint the todos rect_y = compute_flag_ypos(block) painter.setBrush(self._facecolors['todo']) painter.setPen(self._edgecolors['todo']) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint all the breakpoints flags for block, data in self._breakpoint_list: if not should_paint_block(block): continue # Paint the breakpoints rect_y = compute_flag_ypos(block) painter.setBrush(self._facecolors['breakpoint']) painter.setPen(self._edgecolors['breakpoint']) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint the occurrences of selected word flags if editor.occurrences: painter.setBrush(self._facecolors['occurrence']) painter.setPen(self._edgecolors['occurrence']) for line_number in editor.occurrences: if paint_local and not ( min_line <= line_number + 1 <= max_line): continue block = editor.document().findBlockByNumber(line_number) rect_y = compute_flag_ypos(block) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint the found results flags if editor.found_results: painter.setBrush(self._facecolors['found_results']) painter.setPen(self._edgecolors['found_results']) for line_number in editor.found_results: if paint_local and not ( min_line <= line_number + 1 <= max_line): continue block = editor.document().findBlockByNumber(line_number) rect_y = compute_flag_ypos(block) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down if self.slider: cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = editor.rect().contains( editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if is_over_self or (alt and is_over_editor): painter.setPen(self._slider_range_color) painter.setBrush(self._slider_range_brush) x, y, width, height = self.make_slider_range( cursor_pos, scale_factor, offset, groove_rect) painter.drawRect(x, y, width, height) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area """ make_flag = self.make_flag_qrect # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # Paint warnings and todos block = self.editor.document().firstBlock() for line_number in range(self.editor.document().blockCount()+1): data = block.userData() if data: if data.code_analysis: # Paint the warnings color = self.editor.warning_color for source, code, severity, message in data.code_analysis: error = severity == DiagnosticSeverity.ERROR if error: color = self.editor.error_color break self.set_painter(painter, color) painter.drawRect(make_flag(line_number)) if data.todo: # Paint the todos self.set_painter(painter, self.editor.todo_color) painter.drawRect(make_flag(line_number)) if data.breakpoint: # Paint the breakpoints self.set_painter(painter, self.editor.breakpoint_color) painter.drawRect(make_flag(line_number)) block = block.next() # Paint the occurrences if self.editor.occurrences: self.set_painter(painter, self.editor.occurrence_color) for line_number in self.editor.occurrences: painter.drawRect(make_flag(line_number)) # Paint the found results if self.editor.found_results: self.set_painter(painter, self.editor.found_results_color) for line_number in self.editor.found_results: painter.drawRect(make_flag(line_number)) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = self.editor.rect().contains( self.editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if ((is_over_self or (alt and is_over_editor)) and self.slider): pen_color = QColor(Qt.gray) pen_color.setAlphaF(.85) painter.setPen(pen_color) brush_color = QColor(Qt.gray) brush_color.setAlphaF(.5) painter.setBrush(QBrush(brush_color)) painter.drawRect(self.make_slider_range(cursor_pos)) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False
def drawInnerBackground(self, p: QPainter, innerRect: QRectF): if self.m_barStyle == self.BarStyle.DONUT: p.setBrush(self.palette().base()) p.drawEllipse(innerRect)
def paintEvent(self, evt): # get the widget dimensions orig_width = self.width() orig_height = self.height() # fill perc % of the widget perc = 1 width = int(orig_width * perc) height = int(orig_height * perc) # get the starting origin x_orig = int((orig_width - width) / 2) # we want to start at the bottom and draw up. y_orig = orig_height - int((orig_height - height) / 2) # a running x-position running_pos = x_orig # calculate to number of bars nbars = len(self.counts) # calculate the bar widths, this compilcation is # necessary because integer trunction severly cripples # the layout. remainder = width % nbars bar_width = [int(width / nbars)] * nbars for i in range(remainder): bar_width[i] += 1 paint = QPainter() paint.begin(self) # determine the scaling factor max_val = np.max(self.counts) scale = 1. * height / max_val # determine if we have a colormap and drop into the appopriate # loop. if hasattr(self.colormap[0], '__iter__'): # assume we have a colormap for i in range(len(self.counts)): bar_height = self.counts[i] r, g, b = self.colormap[i] paint.setPen(QColor(r, g, b)) paint.setBrush(QColor(r, g, b)) paint.drawRect(running_pos, y_orig, bar_width[i], -bar_height) running_pos += bar_width[i] else: # we have a tuple r, g, b = self.colormap paint.setPen(QColor(r, g, b)) paint.setBrush(QColor(r, g, b)) for i in range(len(self.counts)): bar_height = self.counts[i] * scale paint.drawRect(running_pos, y_orig, bar_width[i], -bar_height) running_pos += bar_width[i] paint.end()
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area """ # The area in which the slider handle of the scrollbar may move. groove_rect = self.get_scrollbar_groove_rect() # The scrollbar's scale factor ratio between pixel span height and # value span height scale_factor = groove_rect.height() / self.get_scrollbar_value_height() # The vertical offset of the scroll flag area relative to the # top of the text editor. offset = groove_rect.y() # Note that we calculate the pixel metrics required to draw the flags # here instead of using the convenience methods of the ScrollFlagArea # for performance reason. rect_x = ceil(self.FLAGS_DX / 2) rect_w = self.WIDTH - self.FLAGS_DX rect_h = self.FLAGS_DY # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # Paint warnings and todos block = self.editor.document().firstBlock() for line_number in range(self.editor.document().blockCount() + 1): data = block.userData() if data: if data.code_analysis: # Paint the warnings for source, code, severity, message in data.code_analysis: error = severity == DiagnosticSeverity.ERROR if error: painter.setBrush(self._facecolors['error']) painter.setPen(self._edgecolors['error']) break else: painter.setBrush(self._facecolors['warning']) painter.setPen(self._edgecolors['warning']) rect_y = self.calcul_flag_ypos(line_number, scale_factor, offset) painter.drawRect(rect_x, rect_y, rect_w, rect_h) if data.todo: # Paint the todos rect_y = self.calcul_flag_ypos(line_number, scale_factor, offset) painter.setBrush(self._facecolors['todo']) painter.setPen(self._edgecolors['todo']) painter.drawRect(rect_x, rect_y, rect_w, rect_h) if data.breakpoint: # Paint the breakpoints rect_y = self.calcul_flag_ypos(line_number, scale_factor, offset) painter.setBrush(self._facecolors['breakpoint']) painter.setPen(self._edgecolors['breakpoint']) painter.drawRect(rect_x, rect_y, rect_w, rect_h) block = block.next() # Paint the occurrences if self.editor.occurrences: painter.setBrush(self._facecolors['occurrence']) painter.setPen(self._edgecolors['occurrence']) for line_number in self.editor.occurrences: rect_y = self.calcul_flag_ypos(line_number, scale_factor, offset) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint the found results if self.editor.found_results: painter.setBrush(self._facecolors['found_results']) painter.setPen(self._edgecolors['found_results']) for line_number in self.editor.found_results: rect_y = self.calcul_flag_ypos(line_number, scale_factor, offset) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down if self.slider: cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = self.editor.rect().contains( self.editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if is_over_self or (alt and is_over_editor): painter.setPen(self._slider_range_color) painter.setBrush(self._slider_range_brush) x, y, width, height = self.make_slider_range( cursor_pos, scale_factor, offset, groove_rect) painter.drawRect(x, y, width, height) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False