def __updateGeometry(self): # type: () -> None """ Update the shadow geometry to fit the widget's changed geometry. """ assert self.__widget is not None widget = self.__widget parent = self.__widgetParent radius = self.radius_ offset = self.__offset pos = widget.pos() if parent is not None and parent != widget.parentWidget(): pos = widget.parentWidget().mapTo(parent, pos) geom = QRect(pos, widget.size()) geom = geom.adjusted(-radius, -radius, radius, radius) geom = geom.translated(offset) if geom != self.geometry(): self.setGeometry(geom) # Set the widget mask (punch a hole through to the `widget` instance. rect = self.rect() mask = QRegion(rect) rect = rect.adjusted(radius, radius, -radius, -radius) rect = rect.translated(-offset) transparent = QRegion(rect) mask = mask.subtracted(transparent) self.setMask(mask)
def __updateGeometry(self): """ Update the shadow geometry to fit the widget's changed geometry. """ widget = self.__widget parent = self.__widgetParent radius = self.radius_ pos = widget.pos() if parent != widget.parentWidget(): pos = widget.parentWidget().mapTo(parent, pos) geom = QRect(pos, widget.size()) geom.adjust(-radius, -radius, radius, radius) if geom != self.geometry(): self.setGeometry(geom) # Set the widget mask (punch a hole through to the `widget` instance. rect = self.rect() mask = QRegion(rect) transparent = QRegion(rect.adjusted(radius, radius, -radius, -radius)) mask = mask.subtracted(transparent) self.setMask(mask)
def update_map(self): """Get current view box to calculate which tiles to draw.""" [min_x, max_x], [min_y, max_y] = self.view_box.viewRange() new_zoom = self.view_box.get_zoom() self.zoom_changed = self.tz != new_zoom self.tz = new_zoom # flip y to calculate edge tiles tile_min_x, tile_max_y = norm2tile(min_x, 1 - min_y, self.tz) tile_max_x, tile_min_y = norm2tile(max_x, 1 - max_y, self.tz) # round them to get edge tiles x, y tile_min_x = max(int(np.floor(tile_min_x)), 0) tile_min_y = max(int(np.floor(tile_min_y)), 0) tile_max_x = min(int(np.ceil(tile_max_x)), 2**self.tz) tile_max_y = min(int(np.ceil(tile_max_y)), 2**self.tz) self.ts = QRect(tile_min_x, tile_min_y, tile_max_x - tile_min_x, tile_max_y - tile_min_y) # transform rounded tile coordinates back min_edge_x, min_edge_y = tile2norm(tile_min_x, tile_min_y, self.tz) max_edge_x, max_edge_y = tile2norm(tile_max_x, tile_max_y, self.tz) # flip y back to transform map min_edge_y, max_edge_y = 1 - min_edge_y, 1 - max_edge_y # rectangle where to put the map into self.ts_norm = QRectF(min_edge_x, min_edge_y, max_edge_x - min_edge_x, max_edge_y - min_edge_y) self._map_z_shift() self._load_new_map()
def __init__(self): self.tile_provider = TILE_PROVIDERS[DEFAULT_TILE_PROVIDER] self.tile_attribution = AttributionItem( parent=self.plot_widget.getViewBox()) self.tile_attribution.setHtml(self.tile_provider.attribution) self.mem_cache = {} self.map = None # type: Optional[Image.Image] # we use a background map so transitions between zoom levels looks nicer self.b_map_item = None self.map_item = None self.__new_map_items() self.ts = QRect(0, 0, 1, 1) self.ts_norm = QRect(0, 0, 1, 1) self.tz = 1 self.zoom_changed = False self.loader = ImageLoader(self) self.futures = [] self.view_box.setAspectLocked(lock=True, ratio=1) self.view_box.sigRangeChangedManually.connect(self.update_map) self.view_box.set_tile_provider(self.tile_provider)
def decorate_welcome_icon(icon, background_color): """Return a `QIcon` with a circle shaped background. """ welcome_icon = QIcon() sizes = [32, 48, 64, 80, 128, 256] background_color = NAMED_COLORS.get(background_color, background_color) background_color = QColor(background_color) grad = radial_gradient(background_color) for size in sizes: icon_size = QSize(5 * size / 8, 5 * size / 8) icon_rect = QRect(QPoint(0, 0), icon_size) pixmap = QPixmap(size, size) pixmap.fill(Qt.transparent) p = QPainter(pixmap) p.setRenderHint(QPainter.Antialiasing, True) p.setBrush(QBrush(grad)) p.setPen(Qt.NoPen) ellipse_rect = QRect(0, 0, size, size) p.drawEllipse(ellipse_rect) icon_rect.moveCenter(ellipse_rect.center()) icon.paint(p, icon_rect, Qt.AlignCenter, ) p.end() welcome_icon.addPixmap(pixmap) return welcome_icon
def __setControlAreaVisible(self, visible): # type: (bool) -> None if self.__splitter is None or self.__splitter.count() < 2: return self.controlAreaVisible = visible splitter = self.__splitter # type: QSplitter w = splitter.widget(0) # Set minimum width to 1 (overrides minimumSizeHint) when control area # is not visible to allow the main area to shrink further. Reset the # minimum width with a 0 if control area is visible. w.setMinimumWidth(int(not visible)) sizes = splitter.sizes() current_size = sizes[0] if bool(current_size) == visible: return current_width = w.width() geom = self.geometry() frame = self.frameGeometry() framemargins = QMargins( frame.left() - geom.left(), frame.top() - geom.top(), frame.right() - geom.right(), frame.bottom() - geom.bottom() ) splitter.setSizes([int(visible), QWIDGETSIZE_MAX]) if not self.isWindow() or \ self.windowState() not in [Qt.WindowNoState, Qt.WindowActive]: # not a window or not in state where we can move move/resize return # force immediate resize recalculation splitter.refresh() self.layout().invalidate() self.layout().activate() if visible: # move left and expand by the exposing widget's width diffx = -w.width() diffw = w.width() else: # move right and shrink by the collapsing width diffx = current_width diffw = -current_width newgeom = QRect( geom.x() + diffx, geom.y(), geom.width() + diffw, geom.height() ) # bound/move by available geometry bounds = QApplication.desktop().availableGeometry(self) bounds = bounds.adjusted( framemargins.left(), framemargins.top(), -framemargins.right(), -framemargins.bottom() ) newsize = newgeom.size().boundedTo(bounds.size()) newgeom = QRect(newgeom.topLeft(), newsize) newgeom.moveLeft(max(newgeom.left(), bounds.left())) newgeom.moveRight(min(newgeom.right(), bounds.right())) self.setGeometry(newgeom)
def setTextRect(self, rect): # type: (QRect) -> None """ Set the rectangle (:class:`QRect`) in which to show the message text. """ if self.__textRect != rect: self.__textRect = QRect(rect) self.update()
def _subControlRect(self, subcontrol): if subcontrol == QStyle.SC_SliderGroove: return self.rect() if subcontrol == QStyle.SC_SliderHandle: if self.orientation() == Qt.Horizontal: return QRect(-self._HANDLE_WIDTH / 2, 0, self._HANDLE_WIDTH, self.rect().height()) else: return QRect(0, -self._HANDLE_WIDTH / 2, self.rect().width(), self._HANDLE_WIDTH)
def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton and self.__dragging: r1, c1 = self._cellAt(event.buttonDownPos(Qt.LeftButton)) r2, c2 = self._cellCloseTo(event.pos()) selrange = QRect(c1, r1, 1, 1).united(QRect(c2, r2, 1, 1)) self.__elastic_band_select(selrange, self.Select) super().mouseMoveEvent(event) event.accept()
def addWidget(self, w): QStackedLayout.addWidget(self, w) rect = self.__rect hint = w.sizeHint() geom = QRect(rect) size = clipMinMax(rect.size(), w.minimumSize(), w.maximumSize()) size = fixSizePolicy(size, hint, w.sizePolicy()) geom.setSize(size) if geom != w.geometry(): w.setGeometry(geom)
def setGeometry(self, rect): QStackedLayout.setGeometry(self, rect) for i in range(self.count()): w = self.widget(i) hint = w.sizeHint() geom = QRect(rect) size = clipMinMax(rect.size(), w.minimumSize(), w.maximumSize()) size = fixSizePolicy(size, hint, w.sizePolicy()) geom.setSize(size) if geom != w.geometry(): w.setGeometry(geom)
def fitRect(rect, targetrect): size = rect.size().boundedTo(targetgeom.size()) newrect = QRect(rect.topLeft(), size) dx, dy = 0, 0 if newrect.left() < targetrect.left(): dx = targetrect.left() - newrect.left() if newrect.top() < targetrect.top(): dy = targetrect.top() - newrect.top() if newrect.right() > targetrect.right(): dx = targetrect.right() - newrect.right() if newrect.bottom() > targetrect.bottom(): dy = targetrect.bottom() - newrect.bottom() return newrect.translated(dx, dy)
def paintEvent(self, event): # based on # https://github.com/qt/qtbase/blob/f40dbe0d0b54ce83d2168e82905cf4f75059a841/src/widgets/widgets/qslider.cpp#L315 # https://github.com/enthought/traitsui/blob/master/traitsui/qt4/extra/range_slider.py painter = QStylePainter(self) minpos = self._min_position maxpos = self._max_position # Draw the groove opt = QStyleOptionSlider() self.initStyleOption(opt) # Draw empty grove opt.sliderPosition = opt.minimum opt.subControls = QStyle.SC_SliderGroove if self.tickPosition() != self.NoTicks: opt.subControls |= QStyle.SC_SliderTickmarks painter.drawComplexControl(QStyle.CC_Slider, opt) # Draw the highlighted part on top # Qt4.8 and Qt5.3 draw the highlighted groove in a weird way because they # transpose opt.rect. Qt5.7 works fine. if QT_VERSION_STR >= '5.7.0': opt.subControls = QStyle.SC_SliderGroove opt.sliderPosition = opt.maximum if self.orientation() == Qt.Horizontal: _w = opt.rect.width() / opt.maximum x = round(_w * minpos) w = round(_w * (maxpos - minpos)) opt.rect = QRect(x, 0, w, opt.rect.height()) else: _h = opt.rect.height() / opt.maximum y = round(_h * minpos) h = round(_h * (maxpos - minpos)) opt.rect = QRect(0, y, opt.rect.width(), h) painter.drawComplexControl(QStyle.CC_Slider, opt) # Draw the handles for i, position in enumerate((minpos, maxpos)): opt = QStyleOptionSlider() self.initStyleOption(opt) opt.subControls = QStyle.SC_SliderHandle if self.__pressed_control and (self.__active_slider == i or self.__active_slider < 0): opt.activeSubControls = self.__pressed_control opt.state |= QStyle.State_Sunken else: opt.activeSubControls = self.__hovered_control opt.sliderPosition = position opt.sliderValue = position painter.drawComplexControl(QStyle.CC_Slider, opt)
def mousePressEvent(self, event): if event.button() == Qt.LeftButton: r, c = self._cellAt(event.pos()) if r != -1 and c != -1: # Clear existing selection # TODO: Fix extended selection. self.__select(QRect(), self.Clear) selrange = QRect(c, r, 1, 1) self.__elastic_band_select(selrange, self.Select | self.Clear) elif event.button() == Qt.RightButton: self.__select(QRect(), self.Clear) super().mousePressEvent(event) event.accept()
def decorate_welcome_icon(icon, background_color): """Return a `QIcon` with a circle shaped background. """ welcome_icon = QIcon() sizes = [32, 48, 64, 80] background_color = NAMED_COLORS.get(background_color, background_color) background_color = QColor(background_color) grad = radial_gradient(background_color) for size in sizes: icon_pixmap = icon.pixmap(5 * size / 8, 5 * size / 8) icon_size = icon_pixmap.size() icon_rect = QRect(QPoint(0, 0), icon_size) pixmap = QPixmap(size, size) pixmap.fill(QColor(0, 0, 0, 0)) p = QPainter(pixmap) p.setRenderHint(QPainter.Antialiasing, True) p.setBrush(QBrush(grad)) p.setPen(Qt.NoPen) ellipse_rect = QRect(0, 0, size, size) p.drawEllipse(ellipse_rect) icon_rect.moveCenter(ellipse_rect.center()) p.drawPixmap(icon_rect.topLeft(), icon_pixmap) p.end() welcome_icon.addPixmap(pixmap) return welcome_icon
def test_popup_util(self): geom = QRect(10, 10, 100, 400) screen = QRect(0, 0, 600, 600) g1 = combobox.dropdown_popup_geometry(geom, QRect(200, 100, 100, 20), screen) self.assertEqual(g1, QRect(200, 120, 100, 400)) g2 = combobox.dropdown_popup_geometry(geom, QRect(-10, 0, 100, 20), screen) self.assertEqual(g2, QRect(0, 20, 100, 400)) g3 = combobox.dropdown_popup_geometry(geom, QRect(590, 0, 100, 20), screen) self.assertEqual(g3, QRect(600 - 100, 20, 100, 400)) g4 = combobox.dropdown_popup_geometry(geom, QRect(0, 500, 100, 20), screen) self.assertEqual(g4, QRect(0, 500 - 400, 100, 400))
def __updateWindowGeometry(self): if not self.isWindow() or self.__hasExplicitSize: return def framemargins(widget): frame, geom = widget.frameGeometry(), widget.geometry() return QMargins(geom.left() - frame.left(), geom.top() - frame.top(), geom.right() - frame.right(), geom.bottom() - frame.bottom()) def fitRect(rect, targetrect): size = rect.size().boundedTo(targetgeom.size()) newrect = QRect(rect.topLeft(), size) dx, dy = 0, 0 if newrect.left() < targetrect.left(): dx = targetrect.left() - newrect.left() if newrect.top() < targetrect.top(): dy = targetrect.top() - newrect.top() if newrect.right() > targetrect.right(): dx = targetrect.right() - newrect.right() if newrect.bottom() > targetrect.bottom(): dy = targetrect.bottom() - newrect.bottom() return newrect.translated(dx, dy) margins = framemargins(self) minsize = QSize(120, 120) pixsize = self.__pixmap.size() available = QApplication.desktop().availableGeometry(self) available = available.adjusted(margins.left(), margins.top(), -margins.right(), -margins.bottom()) # extra adjustment so the preview does not cover the whole desktop available = available.adjusted(10, 10, -10, -10) targetsize = pixsize.boundedTo(available.size()).expandedTo(minsize) pixsize.scale(targetsize, Qt.KeepAspectRatio) if not self.testAttribute(Qt.WA_WState_Created) or \ self.testAttribute(Qt.WA_WState_Hidden): center = available.center() else: center = self.geometry().center() targetgeom = QRect(QPoint(0, 0), pixsize) targetgeom.moveCenter(center) if not available.contains(targetgeom): targetgeom = fitRect(targetgeom, available) self.__inUpdateWindowGeometry = True self.setGeometry(targetgeom) self.__inUpdateWindowGeometry = False
def __shadowPixmapForDpr(self, dpr=1.0): # type: (float) -> QPixmap """ Return a shadow pixmap rendered in `dpr` device pixel ratio. """ offset = self.offset() radius = self.radius() color = self.color() fill_color = self.palette().color(QPalette.Window) rect_size = QSize(int(50 * dpr), int(50 * dpr)) left = top = right = bottom = int(radius * dpr) # Size of the pixmap. pixmap_size = QSize(rect_size.width() + left + right, rect_size.height() + top + bottom) shadow_rect = QRect(QPoint(left, top) - offset * dpr, rect_size) pixmap = QPixmap(pixmap_size) pixmap.fill(Qt.transparent) pixmap = render_drop_shadow_frame( pixmap, QRectF(shadow_rect), shadow_color=color, offset=QPointF(offset * dpr), radius=radius * dpr, rect_fill_color=fill_color ) pixmap.setDevicePixelRatio(dpr) return pixmap
def paint(self, painter, option, index): if option.widget is not None: style = option.widget.style() else: style = QApplication.instance().style() style.drawPrimitive(QStyle.PE_PanelItemViewRow, option, painter, option.widget) style.drawPrimitive(QStyle.PE_PanelItemViewItem, option, painter, option.widget) rect = option.rect val = index.data(Qt.DisplayRole) if isinstance(val, float): if np.isfinite(val): minv, maxv = self.scale val = (val - minv) / (maxv - minv) rect = rect.adjusted(1, 1, -int(rect.width() * (1.0 - val)) - 2, -2) else: rect = QRect() painter.save() if option.state & QStyle.State_Selected: painter.setOpacity(0.75) painter.setBrush(self.brush) painter.drawRect(rect) painter.restore()
def test_splashscreen(self): splash = pkg_resources.resource_filename( config.__package__, "icons/orange-canvas-core-splash.svg" ) w = SplashScreen() w.setPixmap(QPixmap(splash)) w.setTextRect(QRect(100, 100, 400, 50)) w.show() def advance_time(): now = datetime.now() time = now.strftime("%c : %f") i = now.second % 3 if i == 2: w.setTextFormat(Qt.RichText) time = "<i>" + time + "</i>" else: w.setTextFormat(Qt.PlainText) w.showMessage(time, alignment=Qt.AlignCenter) rect = QRect(100, 100 + i * 20, 400, 50) w.setTextRect(rect) self.assertEqual(w.textRect(), rect) timer = QTimer(w, interval=1) timer.timeout.connect(advance_time) timer.start() self.app.exec_()
def paintEvent(self, event): # type: (QPaintEvent) -> None if self.__flat: opt = QStyleOptionToolButton() self.initStyleOption(opt) p = QStylePainter(self) p.drawControl(QStyle.CE_ToolButtonLabel, opt) p.end() else: super().paintEvent(event) # paint shadow shadow = innerShadowPixmap(self.__shadowColor, self.size(), self.__shadowPosition, length=self.__shadowLength) p = QPainter(self) rect = self.rect() targetRect = QRect(rect.left() + 1, rect.top() + 1, rect.width() - 2, rect.height() - 2) p.drawPixmap(targetRect, shadow, shadow.rect()) p.end()
def __testaxis(self, event): viewbox = self.parent() widget = event.widget() assert widget is not None view = widget.parent() assert isinstance(view, QGraphicsView) pos = view.mapFromGlobal(event.screenPos()) hitarea = view.mapToScene(QRect(pos - QPoint(2, 2), QSize(4, 4))) hitarea = viewbox.mapFromScene(hitarea) hitarea = viewbox.mapToView(hitarea).boundingRect() center = hitarea.center() if center.x() < 0: hitarea.moveCenter(QPointF(-center.x(), center.y())) cx = self.selection[1][1].x() cy = self.selection[1][1].y() if hitarea.contains(QPointF(cx, cy)): axes = Qt.Horizontal | Qt.Vertical elif hitarea.bottom() > cy > hitarea.top() and hitarea.left() > cx: axes = Qt.Vertical elif hitarea.left() < cx < hitarea.right() and hitarea.bottom() > cy: axes = Qt.Horizontal else: axes = 0 return axes
def __updatePixmap(self): """ Update the cached shadow pixmap. """ rect_size = QSize(50, 50) left = top = right = bottom = self.radius_ # Size of the pixmap. pixmap_size = QSize(rect_size.width() + left + right, rect_size.height() + top + bottom) shadow_rect = QRect(QPoint(left, top), rect_size) pixmap = QPixmap(pixmap_size) pixmap.fill(QColor(0, 0, 0, 0)) rect_fill_color = self.palette().color(QPalette.Window) pixmap = render_drop_shadow_frame( pixmap, QRectF(shadow_rect), shadow_color=self.color_, offset=QPointF(0, 0), radius=self.radius_, rect_fill_color=rect_fill_color, ) self.__shadowPixmap = pixmap self.update()
def splash_screen(): splash_n = random.randint(1, 3) path = pkg_resources.resource_filename( __name__, f"icons/orange-splash-screen-{splash_n:02}.png") pm = QPixmap(path) version = Config.ApplicationVersion if version: version_parsed = LooseVersion(version) version_comp = version_parsed.version version = ".".join(map(str, version_comp[:2])) size = 13 font = QFont("Helvetica") font.setPixelSize(size) metrics = QFontMetrics(font) br = metrics.boundingRect(version) br.moveTopLeft(QPoint(171, 438)) p = QPainter(pm) p.setRenderHint(QPainter.Antialiasing) p.setRenderHint(QPainter.TextAntialiasing) p.setFont(font) p.setPen(QColor("#000000")) p.drawText(br, Qt.AlignLeft, version) p.end() return pm, QRect(23, 24, 200, 20)
def paint(self, painter, option, index): dist = self.distribution(index) if dist is None or self.colors is None: super().paint(painter, option, index) return if option.widget is not None: style = option.widget.style() else: style = QApplication.style() self.initStyleOption(option, index) text = option.text metrics = option.fontMetrics margin = style.pixelMetric(QStyle.PM_FocusFrameHMargin, option, option.widget) + 1 bottommargin = min(margin, 1) rect = option.rect.adjusted(margin, margin, -margin, -bottommargin) textrect = style.subElementRect(QStyle.SE_ItemViewItemText, option, option.widget) # Are the margins included in the subElementRect?? -> No! textrect = textrect.adjusted(margin, margin, -margin, -bottommargin) text = option.fontMetrics.elidedText(text, option.textElideMode, textrect.width()) spacing = max(metrics.leading(), 1) distheight = rect.height() - metrics.height() - spacing distheight = numpy.clip(distheight, 2, metrics.height()) painter.save() painter.setClipRect(option.rect) painter.setFont(option.font) painter.setRenderHint(QPainter.Antialiasing) style.drawPrimitive(QStyle.PE_PanelItemViewRow, option, painter, option.widget) style.drawPrimitive(QStyle.PE_PanelItemViewItem, option, painter, option.widget) if option.state & QStyle.State_Selected: color = option.palette.highlightedText().color() else: color = option.palette.text().color() painter.setPen(QPen(color)) textrect = textrect.adjusted(0, 0, 0, -distheight - spacing) distrect = QRect(textrect.bottomLeft() + QPoint(0, spacing), QSize(rect.width(), distheight)) painter.setPen(QPen(Qt.lightGray, 0.3)) self.drawDistBar(painter, distrect, dist) painter.restore() if text: style.drawItemText(painter, textrect, option.displayAlignment, option.palette, option.state & QStyle.State_Enabled, text)
def splash_screen(): """ """ pm = QPixmap( pkg_resources.resource_filename(__name__, "icons/orange-splash-screen.png")) version = QCoreApplication.applicationVersion() size = 21 if len(version) < 5 else 16 font = QFont("Helvetica") font.setPixelSize(size) font.setBold(True) font.setItalic(True) font.setLetterSpacing(QFont.AbsoluteSpacing, 2) metrics = QFontMetrics(font) br = metrics.boundingRect(version).adjusted(-5, 0, 5, 0) br.moveCenter(QPoint(436, 224)) p = QPainter(pm) p.setRenderHint(QPainter.Antialiasing) p.setRenderHint(QPainter.TextAntialiasing) p.setFont(font) p.setPen(QColor("#231F20")) p.drawText(br, Qt.AlignCenter, version) p.end() return pm, QRect(88, 193, 200, 20)
def __visualRectForSelection(self, rect): h, w = self.image.shape rect = rect.normalized() rect = rect.intersected(QRect(0, 0, w, h)) r1, r2 = rect.top(), rect.bottom() + 1 c1, c2 = rect.left(), rect.right() + 1 return QRectF(QPointF(c1, r1), QPointF(c2, r2))
def advance_time(): now = datetime.now() time = now.strftime("%c : %f") w.showMessage(time, alignment=Qt.AlignCenter) i = now.second % 3 rect = QRect(100, 100 + i * 20, 400, 50) w.setTextRect(rect) self.assertEqual(w.textRect(), rect)
def viewport_rect(self): """ Return the bounding rect of the document's viewport on the scene. """ view = self.document.view() vsize = view.viewport().size() viewportrect = QRect(0, 0, vsize.width(), vsize.height()) return view.mapToScene(viewportrect).boundingRect()
def setGeometry(self, rect): # type: (QRect) -> None if rect == self.__rect: return self.__rect = QRect(rect) super().setGeometry(rect) for i in range(self.count()): w = self.widget(i) hint = w.sizeHint() geom = QRect(rect) size = clipMinMax(rect.size(), w.minimumSize(), w.maximumSize()) size = fixSizePolicy(size, hint, w.sizePolicy()) geom.setSize(size) if geom != w.geometry(): w.setGeometry(geom)
def __init__(self, parent=None, **kwargs): # type: (Union[QWidget, QLayout, None], Any) -> None self.__rect = QRect() if parent is not None: super().__init__(parent, **kwargs) else: super().__init__(**kwargs) self.currentChanged.connect(self._onCurrentChanged)
def decorate_welcome_icon(icon, background_color): # type: (QIcon, Union[QColor, str]) -> QIcon """Return a `QIcon` with a circle shaped background. """ welcome_icon = QIcon() sizes = [32, 48, 64, 80, 128, 256] background_color = NAMED_COLORS.get(background_color, background_color) background_color = QColor(background_color) grad = radial_gradient(background_color) for size in sizes: icon_size = QSize(int(5 * size / 8), int(5 * size / 8)) icon_rect = QRect(QPoint(0, 0), icon_size) pixmap = QPixmap(size, size) pixmap.fill(Qt.transparent) p = QPainter(pixmap) p.setRenderHint(QPainter.Antialiasing, True) p.setBrush(QBrush(grad)) p.setPen(Qt.NoPen) ellipse_rect = QRect(0, 0, size, size) p.drawEllipse(ellipse_rect) icon_rect.moveCenter(ellipse_rect.center()) icon.paint( p, icon_rect, Qt.AlignCenter, ) p.end() welcome_icon.addPixmap(pixmap) return welcome_icon
def __autoScrollAdvance(self): """Advance the auto scroll """ pos = QCursor.pos() pos = self.mapFromGlobal(pos) margin = self.__autoScrollMargin vvalue = self.verticalScrollBar().value() hvalue = self.horizontalScrollBar().value() vrect = QRect(0, 0, self.width(), self.height()) # What should be the speed advance = 10 # We only do auto scroll if the mouse is inside the view. if vrect.contains(pos): if pos.x() < vrect.left() + margin: self.horizontalScrollBar().setValue(hvalue - advance) if pos.y() < vrect.top() + margin: self.verticalScrollBar().setValue(vvalue - advance) if pos.x() > vrect.right() - margin: self.horizontalScrollBar().setValue(hvalue + advance) if pos.y() > vrect.bottom() - margin: self.verticalScrollBar().setValue(vvalue + advance) if self.verticalScrollBar().value() == vvalue and \ self.horizontalScrollBar().value() == hvalue: self.__stopAutoScroll() else: self.__stopAutoScroll() log.debug("Auto scroll advance")
def __layoutActions(self): left, right = self.__actions contents = self.contentsRect() buttonSize = QSize(contents.height(), contents.height()) margins = self.textMargins() if left: geom = QRect(contents.topLeft(), buttonSize) left.button.setGeometry(geom) margins.setLeft(buttonSize.width()) if right: geom = QRect(contents.topRight(), buttonSize) right.button.setGeometry(geom.translated(-buttonSize.width(), 0)) margins.setLeft(buttonSize.width()) self.setTextMargins(margins)
def testArrowContact(self, indices, x, y): if type(indices) != list: indices = [indices] for index in indices: if index >= len(self.attributes) or index < 0: continue int_x = self.transform(xBottom, index) bottom = self.transform(yLeft, self.selection_conditions.get(self.attributes[index], [0, 1])[0]) bottom_rect = QRect(int_x - self.bottom_pixmap.width() / 2, bottom, self.bottom_pixmap.width(), self.bottom_pixmap.height()) if bottom_rect.contains(QPoint(x, y)): return 1, (index, 0) top = self.transform(yLeft, self.selection_conditions.get(self.attributes[index], [0, 1])[1]) top_rect = QRect(int_x - self.top_pixmap.width() / 2, top - self.top_pixmap.height(), self.top_pixmap.width(), self.top_pixmap.height()) if top_rect.contains(QPoint(x, y)): return 1, (index, 1) return 0, (0, 0)
def setGeometry(self, rect): if not isinstance(rect, QRect): raise TypeError("QRect required") if rect == self.__rect: return self.__rect = QRect(rect) super().setGeometry(rect) for i in range(self.count()): w = self.widget(i) hint = w.sizeHint() geom = QRect(rect) size = clipMinMax(rect.size(), w.minimumSize(), w.maximumSize()) size = fixSizePolicy(size, hint, w.sizePolicy()) geom.setSize(size) if geom != w.geometry(): w.setGeometry(geom)
def drawBackground(self, painter, rect): super().drawBackground(painter, rect) if not self.__backgroundIcon.isNull(): painter.setClipRect(rect) vrect = QRect(QPoint(0, 0), self.viewport().size()) vrect = self.mapToScene(vrect).boundingRect() pm = self.__backgroundIcon.pixmap( vrect.size().toSize().boundedTo(QSize(200, 200)) ) pmrect = QRect(QPoint(0, 0), pm.size()) pmrect.moveCenter(vrect.center().toPoint()) if rect.toRect().intersects(pmrect): painter.drawPixmap(pmrect, pm)
def widget_popup_geometry(pos, widget): widget.ensurePolished() if widget.testAttribute(Qt.WA_Resized): size = widget.size() else: size = widget.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(pos) # Adjust the size to fit inside the screen. if size.height() > screen_geom.height(): size.setHeight(screen_geom.height()) if size.width() > screen_geom.width(): size.setWidth(screen_geom.width()) geom = QRect(pos, size) if geom.top() < screen_geom.top(): geom.setTop(screen_geom.top()) if geom.left() < screen_geom.left(): geom.setLeft(screen_geom.left()) bottom_margin = screen_geom.bottom() - geom.bottom() right_margin = screen_geom.right() - geom.right() if bottom_margin < 0: # Falls over the bottom of the screen, move it up. geom.translate(0, bottom_margin) # TODO: right to left locale if right_margin < 0: # Falls over the right screen edge, move the menu to the # other side of pos. geom.translate(-size.width(), 0) return geom
def showPopup(self): # type: () -> None """ Reimplemented from QComboBox.showPopup Popup up a customized view and filter edit line. Note ---- The .popup(), .lineEdit(), .completer() of the base class are not used. """ if self.__popup is not None: # We have user entered state that cannot be disturbed # (entered filter text, scroll offset, ...) return # pragma: no cover if self.count() == 0: return opt = QStyleOptionComboBox() self.initStyleOption(opt) popup = QListView( uniformItemSizes=True, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOff, verticalScrollBarPolicy=Qt.ScrollBarAsNeeded, iconSize=self.iconSize(), ) popup.setFocusProxy(self.__searchline) popup.setParent(self, Qt.Popup | Qt.FramelessWindowHint) popup.setItemDelegate(_ComboBoxListDelegate(popup)) proxy = QSortFilterProxyModel( popup, filterCaseSensitivity=Qt.CaseInsensitive ) proxy.setFilterKeyColumn(self.modelColumn()) proxy.setSourceModel(self.model()) popup.setModel(proxy) root = proxy.mapFromSource(self.rootModelIndex()) popup.setRootIndex(root) self.__popup = popup self.__proxy = proxy self.__searchline.setText("") self.__searchline.setPlaceholderText("Filter...") self.__searchline.setVisible(True) self.__searchline.textEdited.connect(proxy.setFilterFixedString) style = self.style() # type: QStyle popuprect_origin = style.subControlRect( QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxListBoxPopup, self ) # type: QRect popuprect_origin = QRect( self.mapToGlobal(popuprect_origin.topLeft()), popuprect_origin.size() ) editrect = style.subControlRect( QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxEditField, self ) # type: QRect self.__searchline.setGeometry(editrect) desktop = QApplication.desktop() screenrect = desktop.availableGeometry(self) # type: QRect # get the height for the view listrect = QRect() for i in range(min(proxy.rowCount(root), self.maxVisibleItems())): index = proxy.index(i, self.modelColumn(), root) if index.isValid(): listrect = listrect.united(popup.visualRect(index)) if listrect.height() >= screenrect.height(): break window = popup.window() # type: QWidget window.ensurePolished() if window.layout() is not None: window.layout().activate() else: QApplication.sendEvent(window, QEvent(QEvent.LayoutRequest)) margins = qwidget_margin_within(popup.viewport(), window) height = (listrect.height() + 2 * popup.spacing() + margins.top() + margins.bottom()) popup_size = (QSize(popuprect_origin.width(), height) .expandedTo(window.minimumSize()) .boundedTo(window.maximumSize()) .boundedTo(screenrect.size())) popuprect = QRect(popuprect_origin.bottomLeft(), popup_size) popuprect = dropdown_popup_geometry( popuprect, popuprect_origin, screenrect) popup.setGeometry(popuprect) current = proxy.mapFromSource( self.model().index(self.currentIndex(), self.modelColumn(), self.rootModelIndex())) popup.setCurrentIndex(current) popup.scrollTo(current, QAbstractItemView.EnsureVisible) popup.show() popup.setFocus(Qt.PopupFocusReason) popup.installEventFilter(self) popup.viewport().installEventFilter(self) popup.viewport().setMouseTracking(True) self.update() self.__popupTimer.restart()
def paint(self, painter, option, index): rect = QRect(option.rect) is_selected = index.data(VariableSelectionModel.IsSelected) if option.state & QStyle.State_MouseOver: txt = [" Add ", " Remove "][is_selected] txtw = painter.fontMetrics().width(txt) painter.save() painter.setPen(Qt.NoPen) painter.setBrush(QColor("#ccc")) brect = QRect(rect.x() + rect.width() - 8 - txtw, rect.y(), txtw, rect.height()) painter.drawRoundedRect(brect, 4, 4) painter.restore() painter.drawText(brect, Qt.AlignCenter, txt) painter.save() double_pen = painter.pen() double_pen.setWidth(2 * double_pen.width()) if is_selected: next = index.sibling(index.row() + 1, index.column()) if not next.isValid(): painter.setPen(double_pen) painter.drawLine(rect.bottomLeft(), rect.bottomRight()) elif not next.data(VariableSelectionModel.IsSelected): painter.drawLine(rect.bottomLeft(), rect.bottomRight()) elif not index.row(): down = QPoint(0, painter.pen().width()) painter.setPen(double_pen) painter.drawLine(rect.topLeft() + down, rect.topRight() + down) else: prev = index.sibling(index.row() - 1, index.column()) if prev.data(VariableSelectionModel.IsSelected): painter.drawLine(rect.topLeft(), rect.topRight()) painter.restore() super().paint(painter, option, index)
def dropdown_popup_geometry(geometry, origin, screen): # type: (QRect, QRect, QRect) -> QRect """ Move/constrain the geometry for a drop down popup. Parameters ---------- geometry : QRect The base popup geometry if not constrained. origin : QRect The origin rect from which the popup extends. screen : QRect The available screen geometry into which the popup must fit. Returns ------- geometry: QRect Constrained drop down list geometry to fit into screen """ # if the popup geometry extends bellow the screen and there is more room # above the popup origin ... geometry = QRect(geometry) geometry.moveTopLeft(origin.bottomLeft() + QPoint(0, 1)) if geometry.bottom() > screen.bottom() \ and origin.center().y() > screen.center().y(): # ...flip the rect about the origin so it extends upwards geometry.moveBottom(origin.top() - 1) # fixup horizontal position if it extends outside the screen if geometry.left() < screen.left(): geometry.moveLeft(screen.left()) if geometry.right() > screen.right(): geometry.moveRight(screen.right()) # bounded by screen geometry return geometry.intersected(screen)
def popup(self, pos=None, searchText=""): """ Popup the menu at `pos` (in screen coordinates). 'Search' text field is initialized with `searchText` if provided. """ if pos is None: pos = QPoint() self.__clearCurrentItems() self.__search.setText(searchText) patt = QRegExp("(^|\W)"+searchText) patt.setCaseSensitivity(False) self.__suggestPage.setFilterRegExp(patt) UsageStatistics.set_last_search_query(searchText) self.ensurePolished() if self.testAttribute(Qt.WA_Resized) and self.sizeGripEnabled(): size = self.size() else: size = self.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(pos) # Adjust the size to fit inside the screen. if size.height() > screen_geom.height(): size.setHeight(screen_geom.height()) if size.width() > screen_geom.width(): size.setWidth(screen_geom.width()) geom = QRect(pos, size) if geom.top() < screen_geom.top(): geom.setTop(screen_geom.top()) if geom.left() < screen_geom.left(): geom.setLeft(screen_geom.left()) bottom_margin = screen_geom.bottom() - geom.bottom() right_margin = screen_geom.right() - geom.right() if bottom_margin < 0: # Falls over the bottom of the screen, move it up. geom.translate(0, bottom_margin) # TODO: right to left locale if right_margin < 0: # Falls over the right screen edge, move the menu to the # other side of pos. geom.translate(-size.width(), 0) self.setGeometry(geom) self.show() self.setFocusProxy(self.__search)
def __selectionForArea(self, area): r1, c1 = self._cellAt(area.topLeft()) r2, c2 = self._cellAt(area.bottomRight()) selarea = QRect(c1, r1, c2 - c1 + 1, r2 - r1 + 1) return selarea.normalized()
def __layout(self): # position itself over `widget` widget = self.__widget if widget is None: return alignment = self.__alignment policy = self.sizePolicy() if widget.isWindow(): bounds = widget.geometry() else: bounds = QRect(widget.mapToGlobal(QPoint(0, 0)), widget.size()) if self.isWindow(): bounds = bounds else: bounds = QRect(self.parent().mapFromGlobal(bounds.topLeft()), bounds.size()) sh = self.sizeHint() minsh = self.minimumSizeHint() minsize = self.minimumSize() if minsize.isNull(): minsize = minsh maxsize = bounds.size().boundedTo(self.maximumSize()) minsize = minsize.boundedTo(maxsize) effectivesh = sh.expandedTo(minsize).boundedTo(maxsize) hpolicy = policy.horizontalPolicy() vpolicy = policy.verticalPolicy() def getsize(hint, minimum, maximum, policy): if policy == QSizePolicy.Ignored: return maximum elif policy & QSizePolicy.ExpandFlag: return maximum else: return max(hint, minimum) width = getsize(effectivesh.width(), minsize.width(), maxsize.width(), hpolicy) heightforw = self.heightForWidth(width) if heightforw > 0: height = getsize(heightforw, minsize.height(), maxsize.height(), vpolicy) else: height = getsize(effectivesh.height(), minsize.height(), maxsize.height(), vpolicy) size = QSize(width, height) if alignment & Qt.AlignLeft: x = bounds.x() elif alignment & Qt.AlignRight: x = bounds.right() - size.width() else: x = bounds.x() + max(0, bounds.width() - size.width()) // 2 if alignment & Qt.AlignTop: y = bounds.y() elif alignment & Qt.AlignBottom: y = bounds.bottom() - size.height() else: y = bounds.y() + max(0, bounds.height() - size.height()) // 2 geom = QRect(QPoint(x, y), size) self.setGeometry(geom)
def __paintEventNoStyle(self): p = QPainter(self) opt = QStyleOptionToolButton() self.initStyleOption(opt) fm = QFontMetrics(opt.font) palette = opt.palette # highlight brush is used as the background for the icon and background # when the tab is expanded and as mouse hover color (lighter). brush_highlight = palette.highlight() foregroundrole = QPalette.ButtonText if opt.state & QStyle.State_Sunken: # State 'down' pressed during a mouse press (slightly darker). background_brush = brush_darker(brush_highlight, 110) foregroundrole = QPalette.HighlightedText elif opt.state & QStyle.State_MouseOver: background_brush = brush_darker(brush_highlight, 95) foregroundrole = QPalette.HighlightedText elif opt.state & QStyle.State_On: background_brush = brush_highlight foregroundrole = QPalette.HighlightedText else: # The default button brush. background_brush = palette.button() rect = opt.rect icon_area_rect = QRect(rect) icon_area_rect.setRight(int(icon_area_rect.height() * 1.26)) text_rect = QRect(rect) text_rect.setLeft(icon_area_rect.right() + 10) # Background (TODO: Should the tab button have native # toolbutton shape, drawn using PE_PanelButtonTool or even # QToolBox tab shape) # Default outline pen pen = QPen(palette.color(QPalette.Mid)) p.save() p.setPen(Qt.NoPen) p.setBrush(QBrush(background_brush)) p.drawRect(rect) # Draw the background behind the icon if the background_brush # is different. if not opt.state & QStyle.State_On: p.setBrush(brush_highlight) p.drawRect(icon_area_rect) # Line between the icon and text p.setPen(pen) p.drawLine(icon_area_rect.topRight(), icon_area_rect.bottomRight()) if opt.state & QStyle.State_HasFocus: # Set the focus frame pen and draw the border pen = QPen(QColor(FOCUS_OUTLINE_COLOR)) p.setPen(pen) p.setBrush(Qt.NoBrush) # Adjust for pen rect = rect.adjusted(0, 0, -1, -1) p.drawRect(rect) else: p.setPen(pen) # Draw the top/bottom border if self.position == QStyleOptionToolBox.OnlyOneTab or \ self.position == QStyleOptionToolBox.Beginning or \ self.selected & \ QStyleOptionToolBox.PreviousIsSelected: p.drawLine(rect.topLeft(), rect.topRight()) p.drawLine(rect.bottomLeft(), rect.bottomRight()) p.restore() p.save() text = fm.elidedText(opt.text, Qt.ElideRight, text_rect.width()) p.setPen(QPen(palette.color(foregroundrole))) p.setFont(opt.font) p.drawText(text_rect, int(Qt.AlignVCenter | Qt.AlignLeft) | \ int(Qt.TextSingleLine), text) if not opt.icon.isNull(): if opt.state & QStyle.State_Enabled: mode = QIcon.Normal else: mode = QIcon.Disabled if opt.state & QStyle.State_On: state = QIcon.On else: state = QIcon.Off icon_area_rect = icon_area_rect icon_rect = QRect(QPoint(0, 0), opt.iconSize) icon_rect.moveCenter(icon_area_rect.center()) opt.icon.paint(p, icon_rect, Qt.AlignCenter, mode, state) p.restore()
def popup_position_from_source(popup, source, orientation=Qt.Vertical): popup.ensurePolished() source.ensurePolished() if popup.testAttribute(Qt.WA_Resized): size = popup.size() else: size = popup.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(source) source_rect = QRect(source.mapToGlobal(QPoint(0, 0)), source.size()) if orientation == Qt.Vertical: if source_rect.right() + size.width() < screen_geom.right(): x = source_rect.right() else: x = source_rect.left() - size.width() # bottom overflow dy = source_rect.top() + size.height() - screen_geom.bottom() if dy < 0: y = source_rect.top() else: y = source_rect.top() - dy else: # right overflow dx = source_rect.left() + size.width() - screen_geom.right() if dx < 0: x = source_rect.left() else: x = source_rect.left() - dx if source_rect.bottom() + size.height() < screen_geom.bottom(): y = source_rect.bottom() else: y = source_rect.top() - size.height() return QPoint(x, y)