def eventFilter(self, obj: QtWidgets.QAbstractButton, event: QtCore.QEvent): if event.type() == QtCore.QEvent.Type.Enter: # self.tool_tip.adjustSize() self.tool_tip.setText(obj.toolTip()) self.tool_tip.show() position = "bottom" distance = 100 center = obj.rect().center() if position == "top": center.setY(obj.rect().bottom()) delta = core.Point(0, distance) elif position == "bottom": center.setY(obj.rect().top()) delta = core.Point(0, -distance) elif position == "left": center.setX(obj.rect().right()) delta = core.Point(distance, 0) elif position == "right": center.setX(obj.rect().left()) delta = core.Point(-distance, 0) center = obj.mapToGlobal(center) self.slide_anim.set_start_value(center + delta) self.slide_anim.set_end_value(center) self.animation.start_animation() elif event.type() == QtCore.QEvent.Type.Leave: self.tool_tip.hide() self.animation.stop() elif event.type() == QtCore.QEvent.Type.ToolTip: return True return super().eventFilter(obj, event)
def test_spanslider(qtbot, qttester): slider = custom_widgets.SpanSlider() qtbot.add_widget(slider) slider.show() slider.set_lower_value(10) slider.set_upper_value(20) slider.set_lower_pos(15) slider.set_lower_pos(15) slider.set_upper_pos(25) slider.set_upper_pos(25) assert slider.lower_value == 15 assert slider.upper_value == 25 slider.set_value((16, 24)) assert slider.get_value() == (16, 24) slider.set_lower_value(12) slider.set_upper_pos(20) color = gui.Color("blue") slider.set_left_color(color) slider.set_right_color(color) slider._swap_controls() slider.trigger_action(slider.SliderAction.SliderNoAction, True) slider.trigger_action(slider.SliderAction.SliderSingleStepAdd, True) slider.repaint() slider._pixel_pos_to_value(100) slider._move_pressed_handle() qttester.send_mousepress(slider, QtCore.Qt.MouseButton.LeftButton) qttester.send_mousemove(slider, core.Point(20, 20)) qttester.send_mousemove(slider, core.Point(0, 0), delay=10) assert slider.get_movement_mode() == "no_crossing" slider.set_movement_mode("no_overlap") slider.close()
def test_polygon(): rect1 = core.Rect(0, 0, 2, 1) rect2 = core.Rect(1, 0, 2, 1) poly = gui.Polygon(rect1, closed=True) poly2 = gui.Polygon(rect2, closed=True) intersect = poly & poly2 expected = gui.Polygon(core.Rect(1, 0, 1, 1), closed=True) # TODO: breaks PySide2 testing # assert intersect == expected # assert intersect.get_points() == [ # core.Point(1, 0), # core.Point(2, 0), # core.Point(2, 1), # core.Point(1, 1), # core.Point(1, 0), # ] union = poly | poly2 expected = gui.Polygon(core.Rect(0, 0, 3, 1), closed=True) assert list(union) == list(expected) sub = union - intersect xor = poly ^ poly2 assert list(sub) == list(xor) # assert sub == xor with open("data.pkl", "wb") as jar: pickle.dump(poly, jar) with open("data.pkl", "rb") as jar: poly = pickle.load(jar) poly.add_points((0, 1), core.Point(2, 2)) assert bool(poly) is True assert core.Point(1, 0) in poly p = core.Point(5, 5) poly[5] = p assert poly[5] == p bytes(poly)
def get_image(self): image = self.grab() gl_widget = self.findChild(QtWidgets.QOpenGLWidget) if gl_widget: d = gl_widget.mapToGlobal(core.Point()) - self.mapToGlobal(core.Point()) with gui.Painter(image) as painter: painter.set_composition_mode("source_atop") painter.drawImage(d, gl_widget.grabFramebuffer()) return image
def test_line(): line = core.Line() p1 = core.Point(0, 0) p2 = core.Point(1, 0) line[0] = p1 line[1] = p2 assert line[0] == p1 assert line[1] == p2 line2 = core.Line(1, 0, 0, 0) assert line2 == reversed(line) assert abs(line) == 1 for p in line: pass
def __init__(self, duration: int = 1000, easing: core.easingcurve.TypeStr = "in_out_sine"): super().__init__() self.set_easing(easing) self.set_start_value(core.Point(0, 0)) self.setDuration(duration)
def paintEvent(self, event): super().paintEvent(event) painter = gui.Painter(self) metrics = painter.get_font_metrics() did_elide = False line_spacing = metrics.lineSpacing() y = 0 layout = gui.TextLayout(self.content, painter.font()) with layout.process_layout(): while True: line = layout.createLine() if not line.isValid(): break line.setLineWidth(self.width()) next_line_y = y + line_spacing if self.height() >= next_line_y + line_spacing: line.draw(painter, core.Point(0, y)) y = next_line_y else: last_line = self.content[line.textStart():] elided_line = metrics.elided_text(last_line, "right", self.width()) painter.drawText(0, y + metrics.ascent(), elided_line) line = layout.createLine() did_elide = line.isValid() break if did_elide != self.elided: self.elided = did_elide self.elision_changed.emit(did_elide)
def test_labeledslider(qtbot): slider = custom_widgets.LabeledSlider(["test1", "test2"], "vertical") slider = custom_widgets.LabeledSlider(["test1", "test2"]) qtbot.addWidget(slider) qtbot.mouseClick(slider.sl, QtCore.Qt.LeftButton) qtbot.mouseMove(slider.sl, core.Point(20, 20)) slider.paintEvent(None)
def do_layout(self, rect, test_only): x = rect.x() y = rect.y() line_height = 0 for item in self.items: wid = item.widget() pb = widgets.SizePolicy.PushButton space = self.spacing() space_x = space + wid.style().layoutSpacing( pb, pb, QtCore.Qt.Horizontal) next_x = x + item.sizeHint().width() + space_x if next_x - space_x > rect.right() and line_height > 0: x = rect.x() space_y = space + wid.style().layoutSpacing( pb, pb, QtCore.Qt.Vertical) y = y + line_height + space_y next_x = x + item.sizeHint().width() + space_x line_height = 0 if not test_only: item.setGeometry(core.Rect(core.Point(x, y), item.sizeHint())) x = next_x line_height = max(line_height, item.sizeHint().height()) return y + line_height - rect.y()
def do_layout(self, rect: QtCore.QRect, test_only: bool) -> int: x = rect.x() y = rect.y() line_height = 0 space = self.spacing() pb = widgets.SizePolicy.ControlType.PushButton for item in self.items: wid = item.widget() space_x = space + wid.style().layoutSpacing( pb, pb, constants.HORIZONTAL) next_x = x + item.sizeHint().width() + space_x if next_x - space_x > rect.right() and line_height > 0: x = rect.x() space_y = space + wid.style().layoutSpacing( pb, pb, constants.VERTICAL) y = y + line_height + space_y next_x = x + item.sizeHint().width() + space_x line_height = 0 if not test_only: item.setGeometry(core.Rect(core.Point(x, y), item.sizeHint())) x = next_x line_height = max(line_height, item.sizeHint().height()) return y + line_height - rect.y()
def __setitem__(self, index: int, value: types.PointType): if isinstance(value, tuple): p = core.Point(*value) else: p = value # PySide2 workaround: setPoint does not exist self.remove(index) self.insert(index, p)
def paintEvent(self, event): painter = widgets.StylePainter(self) # ticks opt = widgets.StyleOptionSlider() self.initStyleOption(opt) opt.subControls = widgets.Style.SubControl.SC_SliderTickmarks painter.draw_complex_control("slider", opt) # groove opt.sliderPosition = 20 opt.sliderValue = 0 opt.subControls = GROOVE_STYLE painter.draw_complex_control("slider", opt) # handle rects opt.sliderPosition = self.lower_pos lr = self.style().subControlRect(SLIDER_STYLE, opt, HANDLE_STYLE, self) lrv = self.pick(lr.center()) opt.sliderPosition = self.upper_pos ur = self.style().subControlRect(SLIDER_STYLE, opt, HANDLE_STYLE, self) urv = self.pick(ur.center()) # span minv = min(lrv, urv) maxv = max(lrv, urv) c = self.style().subControlRect(SLIDER_STYLE, opt, GROOVE_STYLE, self).center() if self.is_horizontal(): rect = core.Rect(core.Point(minv, c.y() - 2), core.Point(maxv, c.y() + 1)) else: rect = core.Rect(core.Point(c.x() - 2, minv), core.Point(c.x() + 1, maxv)) self._draw_span(painter, rect) # handles if self.last_pressed == "lower": self.draw_handle(painter, "upper") self.draw_handle(painter, "lower") else: self.draw_handle(painter, "lower") self.draw_handle(painter, "upper")
def test_labeledslider(qtbot, qttester): slider = custom_widgets.LabeledSlider(["test1", "test2"], "vertical") slider = custom_widgets.LabeledSlider(["test1", "test2"]) slider.show() qtbot.add_widget(slider) qttester.send_mousepress(slider.sl, QtCore.Qt.MouseButton.LeftButton) qttester.send_mousemove(slider.sl, core.Point(20, 20)) slider.repaint() slider.hide()
def paint( self, painter: QtGui.QPainter, option: QtWidgets.QStyleOptionViewItem, index: QtCore.QModelIndex, ): """Override to paint an icon based on given Pixmap / Color / Icon. Pixmap / Color / Icon must be set to 'QtCore.Qt.ItemDataRole.UserRole + 1000' Args: painter (QtGui.QPainter): painter to paint the icon option (QtWidgets.QStyleOptionViewItem): state of the item to be displayed index (QtCore.QModelIndex): index which gets decorated """ super().paint(painter, option, index) value = index.data(DecorationRole2) if not value: return margin = 10 mode = gui.Icon.Mode.Normal if not (option.state & widgets.Style.StateFlag.State_Enabled): mode = gui.Icon.Mode.Disabled elif option.state & widgets.Style.StateFlag.State_Selected: mode = gui.Icon.Mode.Selected if isinstance(value, QtGui.QPixmap): icon = QtGui.QIcon(value) option.decorationSize = int(value.size() / value.devicePixelRatio()) elif isinstance(value, QtGui.QColor): pixmap = QtGui.QPixmap(option.decorationSize) pixmap.fill(value) icon = QtGui.QIcon(pixmap) elif isinstance(value, QtGui.QImage): icon = QtGui.QIcon(QtGui.QPixmap.fromImage(value)) option.decorationSize = int(value.size() / value.devicePixelRatio()) elif isinstance(value, QtGui.QIcon): is_on = option.state & widgets.Style.StateFlag.State_Open state = gui.Icon.State.On if is_on else gui.Icon.State.Off actual_size = option.icon.actualSize(option.decorationSize, mode, state) option.decorationSize = option.decorationSize & actual_size r = core.Rect(core.Point(), option.decorationSize) r.moveCenter(option.rect.center()) r.setRight(option.rect.right() - margin) state = (gui.Icon.State.On if option.state & widgets.Style.StateFlag.State_Open else gui.Icon.State.Off) alignment = constants.ALIGN_RIGHT | constants.ALIGN_V_CENTER # type: ignore icon.paint(painter, r, alignment, mode, state)
def test_tabwidget(): widget = widgets.TabWidget() widget.add_tab(widgets.Widget(), "mdi.timer") widget.insert_tab(0, widgets.Widget(), "test", "mdi.timer") w = widgets.Widget() widget.add_tab(w, "test", "mdi.timer") assert widget[2] == w widget.set_tab(0, "right", None) widget.set_detachable() widget.detach_tab(0, core.Point()) with open("data.pkl", "wb") as jar: pickle.dump(widget, jar) with open("data.pkl", "rb") as jar: widget = pickle.load(jar) widget.remove_tab(0)
def test_polygonf(): poly = gui.PolygonF() poly.add_points((0, 0), (2, 0), (2, 1), (0, 1)) poly2 = gui.PolygonF() poly2.add_points((1, 0), (3, 0), (3, 1), (1, 1)) with open("data.pkl", "wb") as jar: pickle.dump(poly, jar) with open("data.pkl", "rb") as jar: poly = pickle.load(jar) union = poly | poly2 intersect = poly & poly2 sub = union - intersect xor = poly ^ poly2 assert sub == xor polygon = poly.to_polygon() assert type(polygon) == gui.Polygon poly.add_points((0, 1), core.Point(2, 2)) bytes(poly)
def test_guiapplication(qapp): qapp.set_layout_direction("right_to_left") with pytest.raises(InvalidParamError): qapp.set_layout_direction("test") assert qapp.get_layout_direction() == "right_to_left" qapp.get_font() qapp.get_icon() qapp.get_primary_screen() qapp.get_screens() qapp.get_screen_at(core.Point(1, 1)) assert qapp.get_application_state() in [["inactive"], ["active"]] qapp.copy_to_clipboard("test") qapp.set_icon("mdi.timer") qapp.set_icon(None) qapp.set_high_dpi_scale_factor_rounding_policy("round_prefer_floor") with pytest.raises(InvalidParamError): qapp.set_high_dpi_scale_factor_rounding_policy("testus") assert qapp.get_high_dpi_scale_factor_rounding_policy() == "round_prefer_floor"
def test_tabwidget(): widget = widgets.TabWidget(detachable=True) widget.add_tab(widgets.Widget(), "mdi.timer") widget.insert_tab(0, widgets.Widget(), "test", "mdi.timer") assert len(widget) == 2 w = widgets.Widget() widget.add_tab(w, "test", "mdi.timer") assert widget[2] == w widget.set_tab(0, "right", None) widget.set_detachable() widget.detach_tab(0, core.Point()) with open("data.pkl", "wb") as jar: pickle.dump(widget, jar) with open("data.pkl", "rb") as jar: widget = pickle.load(jar) with pytest.raises(ValueError): widget.set_tab_shape("test") widget.remove_tab(0) widget.add_tab(widgets.BoxLayout("horizontal"), "mdi.timer") widget.close_detached_tabs()
def set_state(self, x, y): xy = [x, y] d = hypot(xy[0], xy[1]) # length nxy = [0, 0] for i in [0, 1]: if xy[i] == 0: nxy[i] = 0 else: nxy[i] = xy[i] / d if d > self.radius: d = self.radius d = (d / self.radius) ** 2 xy = [nxy[0] * d, nxy[1] * d] w2 = self.width() / 2 h2 = self.height() / 2 self.spot_pos = core.Point(int(w2 * (1 + xy[0])), int(h2 * (1 - xy[1]))) self.update() if self.state == xy: return self.state = xy self.state_changed.emit(self.state)
def test_spanslider(qtbot): slider = custom_widgets.SpanSlider() qtbot.addWidget(slider) slider.set_lower_value(10) slider.set_upper_value(20) slider.set_lower_pos(15) slider.set_upper_pos(25) assert slider.lower_value == 15 assert slider.upper_value == 25 slider.set_lower_value(12) slider.set_upper_pos(20) color = gui.Color("blue") slider.set_left_color(color) slider.set_right_color(color) slider.swap_controls() slider.trigger_action(slider.SliderNoAction, True) slider.trigger_action(slider.SliderSingleStepAdd, True) slider.paintEvent(None) slider.pixel_pos_to_value(100) slider.draw_span(gui.Painter(), core.Rect()) slider.move_pressed_handle() qtbot.mouseClick(slider, QtCore.Qt.LeftButton) qtbot.mouseMove(slider, core.Point(20, 20)) assert slider.movement_mode == "free"
def get_point(self, index: int) -> core.Point: # PySide2 doesnt have self.point method return core.Point(self.value(index))
from __future__ import annotations from prettyqt import core, gui from prettyqt.qt import QtCore, QtGui ZERO_COORD = core.Point(0, 0) class CharIconEngine(gui.IconEngine): """Specialization of QtGui.QIconEngine used to draw font-based icons.""" def __init__(self, iconic, options): super().__init__() self.iconic = iconic self.options = options def paint(self, painter: QtGui.QPainter, rect: QtCore.QRect, mode, state): self.iconic.paint(painter, rect, mode, state, self.options) def pixmap(self, size, mode, state) -> QtGui.QPixmap: pm = QtGui.QPixmap(size) pm.fill(QtCore.Qt.GlobalColor.transparent) # type: ignore rect = core.Rect(ZERO_COORD, size) painter = gui.Painter(pm) self.paint(painter, rect, mode, state) return pm
def get_position(self) -> core.Point: return core.Point(self.position())
address = shiboken2.getCppPointer(self.data()) buffer = (ctypes.c_double * 2 * self.size()).from_address(address) else: buffer = self.data() buffer.setsize(16 * self.size()) return buffer @classmethod def from_xy(cls, xdata, ydata) -> PolygonF: import numpy as np size = len(xdata) polyline = cls() buffer = polyline.get_data_buffer(size) memory = np.frombuffer(buffer, np.float64) memory[:(size - 1) * 2 + 1:2] = np.array(xdata, dtype=np.float64, copy=False) memory[1:(size - 1) * 2 + 2:2] = np.array(ydata, dtype=np.float64, copy=False) return polyline if __name__ == "__main__": poly = PolygonF([core.Point(1, 1), core.Point(2, 2)]) poly2 = PolygonF([core.Point(1, 1), core.Point(2, 2)]) new = poly | poly2 print(repr(new))
def set_position(self, point: types.PointType): if isinstance(point, tuple): point = core.Point(*point) self.setPosition(point)
def get_link_at(self, point: types.PointType) -> core.Url: if isinstance(point, tuple): point = core.Point(*point) return core.Url(self.linkAt(point))
def set_start_value(self, point: types.PointType): if isinstance(point, tuple): point = core.Point(*point) self.setStartValue(point)
def set_end_value(self, point: types.PointType): if isinstance(point, tuple): point = core.Point(*point) self.setEndValue(point)
def __reduce__(self): return type(self), (), self.__getstate__() def __getstate__(self): ba = QtCore.QByteArray() stream = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly) stream << self return ba def __setstate__(self, ba): stream = QtCore.QDataStream(ba, QtCore.QIODevice.ReadOnly) stream >> self @classmethod def from_xy(cls, xdata, ydata): import numpy as np size = len(xdata) polyline = cls(size) pointer = polyline.data() dtype, tinfo = np.float, np.finfo # integers: = np.int, np.iinfo pointer.setsize(2 * polyline.size() * tinfo(dtype).dtype.itemsize) memory = np.frombuffer(pointer, dtype) memory[:(size - 1) * 2 + 1:2] = xdata memory[1:(size - 1) * 2 + 2:2] = ydata return polyline if __name__ == "__main__": from prettyqt import core poly = PolygonF((core.Point(1, 1), core.Point(2, 2)))
def add_points(self, *points: types.PointType): for p in points: if isinstance(p, tuple): p = core.Point(*p) self.append(p)