Пример #1
0
 def paintEvent(self, event: QPaintEvent):
     painter = QPainter(self)
     painter.drawImage(self.rect(), self.image)
     if self.show_frame:
         painter.save()
         pen = QPen()
         pen.setWidth(2)
         pen.setColor(QColor("black"))
         painter.setPen(pen)
         rect = QRect(1, 1, self.width() - 2, self.height() - 2)
         painter.drawRect(rect)
         pen.setColor(QColor("white"))
         painter.setPen(pen)
         rect = QRect(3, 3, self.width() - 6, self.height() - 6)
         painter.drawRect(rect)
         painter.restore()
     if self.show_arrow:
         painter.save()
         triangle = QPolygonF()
         dist = 4
         point1 = QPoint(self.width() - self.triangle_width, 0)
         size = QSize(20, self.height() // 2)
         rect = QRect(point1, size)
         painter.fillRect(rect, QColor("white"))
         triangle.append(point1 + QPoint(dist, dist))
         triangle.append(point1 + QPoint(size.width() - dist, dist))
         triangle.append(point1 + QPoint(size.width() // 2,
                                         size.height() - dist))
         painter.setBrush(Qt.black)
         painter.drawPolygon(triangle, Qt.WindingFill)
         painter.restore()
Пример #2
0
    def readSettings(self, settings):
        qapp = QApplication.instance()

        # get the saved window geometry
        window_size = settings.get('MainWindow/size')
        if not isinstance(window_size, QSize):
            window_size = QSize(*window_size)
        window_pos = settings.get('MainWindow/position')
        if not isinstance(window_pos, QPoint):
            window_pos = QPoint(*window_pos)
        if settings.has('MainWindow/font'):
            font_string = settings.get('MainWindow/font').split(',')
            font = QFontDatabase().font(font_string[0], font_string[-1],
                                        int(font_string[1]))
            qapp.setFont(font)

        # reset font for ipython console to ensure it stays monospace
        self.ipythonconsole.console.reset_font()

        # make sure main window is smaller than the desktop
        desktop = QDesktopWidget()

        # this gives the maximum screen number if the position is off screen
        screen = desktop.screenNumber(window_pos)

        # recalculate the window size
        desktop_geom = desktop.availableGeometry(screen)
        w = min(desktop_geom.size().width(), window_size.width())
        h = min(desktop_geom.size().height(), window_size.height())
        window_size = QSize(w, h)

        # and position it on the supplied desktop screen
        x = max(window_pos.x(), desktop_geom.left())
        y = max(window_pos.y(), desktop_geom.top())
        if x + w > desktop_geom.right():
            x = desktop_geom.right() - w
        if y + h > desktop_geom.bottom():
            y = desktop_geom.bottom() - h
        window_pos = QPoint(x, y)

        # set the geometry
        self.resize(window_size)
        self.move(window_pos)

        # restore window state
        if settings.has('MainWindow/state'):
            if not self.restoreState(settings.get('MainWindow/state'),
                                     SAVE_STATE_VERSION):
                logger.warning(
                    "The previous layout of workbench is not compatible with this version, reverting to default layout."
                )
        else:
            self.setWindowState(Qt.WindowMaximized)

        # read in settings for children
        AlgorithmInputHistory().readSettings(settings)
        for widget in self.widgets:
            if hasattr(widget, 'readSettingsIfNotDone'):
                widget.readSettingsIfNotDone(settings)
Пример #3
0
    def readSettings(self, settings):
        qapp = QApplication.instance()
        qapp.setAttribute(Qt.AA_UseHighDpiPixmaps)
        if hasattr(Qt, 'AA_EnableHighDpiScaling'):
            qapp.setAttribute(Qt.AA_EnableHighDpiScaling,
                              settings.get('high_dpi_scaling'))

        # get the saved window geometry
        window_size = settings.get('MainWindow/size')
        if not isinstance(window_size, QSize):
            window_size = QSize(*window_size)
        window_pos = settings.get('MainWindow/position')
        if not isinstance(window_pos, QPoint):
            window_pos = QPoint(*window_pos)
        if settings.has('MainWindow/font'):
            font_string = settings.get('MainWindow/font').split(',')
            font = QFontDatabase().font(font_string[0], font_string[-1],
                                        int(font_string[1]))
            qapp.setFont(font)

        # make sure main window is smaller than the desktop
        desktop = QDesktopWidget()

        # this gives the maximum screen number if the position is off screen
        screen = desktop.screenNumber(window_pos)

        # recalculate the window size
        desktop_geom = desktop.availableGeometry(screen)
        w = min(desktop_geom.size().width(), window_size.width())
        h = min(desktop_geom.size().height(), window_size.height())
        window_size = QSize(w, h)

        # and position it on the supplied desktop screen
        x = max(window_pos.x(), desktop_geom.left())
        y = max(window_pos.y(), desktop_geom.top())
        if x + w > desktop_geom.right():
            x = desktop_geom.right() - w
        if y + h > desktop_geom.bottom():
            y = desktop_geom.bottom() - h
        window_pos = QPoint(x, y)

        # set the geometry
        self.resize(window_size)
        self.move(window_pos)

        # restore window state
        if settings.has('MainWindow/state'):
            self.restoreState(settings.get('MainWindow/state'))
        else:
            self.setWindowState(Qt.WindowMaximized)

        # read in settings for children
        AlgorithmInputHistory().readSettings(settings)
        for widget in self.widgets:
            if hasattr(widget, 'readSettings'):
                widget.readSettings(settings)
Пример #4
0
def qwtScaleBoundingRect(graphic, size):
    scaledSize = QSize(size)
    if scaledSize.isEmpty():
        scaledSize = graphic.defaultSize()
    sz = graphic.controlPointRect().size()
    sx = 1.0
    if sz.width() > 0.0:
        sx = scaledSize.width() / sz.width()
    sy = 1.0
    if sz.height() > 0.0:
        sy = scaledSize.height() / sz.height()
    return graphic.scaledBoundingRect(sx, sy)
    def SetInitialSize(self, size: QC.QSize):

        display_size = ClientGUIFunctions.GetDisplaySize(self)

        width = min(display_size.width(), size.width())
        height = min(display_size.height(), size.height())

        self.resize(QC.QSize(width, height))

        min_width = min(240, width)
        min_height = min(240, height)

        self.setMinimumSize(QC.QSize(min_width, min_height))
Пример #6
0
 def __honour_image_aspect_ratio(self):
     ''' resizes the window to fit the image aspect ratio based on the chart size '''
     if len(self.image.text()) > 0:
         width, height = Image.open(self.image.text()).size
         width_delta = width - self.__x
         height_delta = height - self.__y
         if width_delta != 0 or height_delta != 0:
             win_size = self.size()
             target_size = QSize(win_size.width() + width_delta,
                                 win_size.height() + height_delta)
             available_size = QDesktopWidget().availableGeometry()
             if available_size.width() < target_size.width(
             ) or available_size.height() < target_size.height():
                 target_size.scale(available_size.width() - 48,
                                   available_size.height() - 48,
                                   Qt.KeepAspectRatio)
             self.resize(target_size)
Пример #7
0
    def readSettings(self, settings):
        qapp = QApplication.instance()
        qapp.setAttribute(Qt.AA_UseHighDpiPixmaps)
        if hasattr(Qt, 'AA_EnableHighDpiScaling'):
            qapp.setAttribute(Qt.AA_EnableHighDpiScaling, settings.get('high_dpi_scaling'))

        # get the saved window geometry
        window_size = settings.get('MainWindow/size')
        if not isinstance(window_size, QSize):
            window_size = QSize(*window_size)
        window_pos = settings.get('MainWindow/position')
        if not isinstance(window_pos, QPoint):
            window_pos = QPoint(*window_pos)

        # make sure main window is smaller than the desktop
        desktop = QDesktopWidget()

        # this gives the maximum screen number if the position is off screen
        screen = desktop.screenNumber(window_pos)

        # recalculate the window size
        desktop_geom = desktop.screenGeometry(screen)
        w = min(desktop_geom.size().width(), window_size.width())
        h = min(desktop_geom.size().height(), window_size.height())
        window_size = QSize(w, h)

        # and position it on the supplied desktop screen
        x = max(window_pos.x(), desktop_geom.left())
        y = max(window_pos.y(), desktop_geom.top())
        window_pos = QPoint(x, y)

        # set the geometry
        self.resize(window_size)
        self.move(window_pos)

        # restore window state
        if settings.has('MainWindow/state'):
            self.restoreState(settings.get('MainWindow/state'))
        else:
            self.setWindowState(Qt.WindowMaximized)

        # read in settings for children
        AlgorithmInputHistory().readSettings(settings)
        for widget in self.widgets:
            if hasattr(widget, 'readSettings'):
                widget.readSettings(settings)
Пример #8
0
    def readSettings(self, settings):
        qapp = QApplication.instance()
        qapp.setAttribute(Qt.AA_UseHighDpiPixmaps)
        if hasattr(Qt, 'AA_EnableHighDpiScaling'):
            qapp.setAttribute(Qt.AA_EnableHighDpiScaling,
                              settings.get('main/high_dpi_scaling'))

        # get the saved window geometry
        window_size = settings.get('main/window/size')
        if not isinstance(window_size, QSize):
            window_size = QSize(*window_size)
        window_pos = settings.get('main/window/position')
        if not isinstance(window_pos, QPoint):
            window_pos = QPoint(*window_pos)

        # make sure main window is smaller than the desktop
        desktop = QDesktopWidget()

        # this gives the maximum screen number if the position is off screen
        screen = desktop.screenNumber(window_pos)

        # recalculate the window size
        desktop_geom = desktop.screenGeometry(screen)
        w = min(desktop_geom.size().width(), window_size.width())
        h = min(desktop_geom.size().height(), window_size.height())
        window_size = QSize(w, h)

        # and position it on the supplied desktop screen
        x = max(window_pos.x(), desktop_geom.left())
        y = max(window_pos.y(), desktop_geom.top())
        window_pos = QPoint(x, y)

        # set the geometry
        self.resize(window_size)
        self.move(window_pos)

        # restore window state
        if settings.has('main/window/state'):
            self.restoreState(settings.get('main/window/state'))
        else:
            self.setWindowState(Qt.WindowMaximized)

        # have algorithm dialogs do their thing
        AlgorithmInputHistory().readSettings(settings)
Пример #9
0
def ExpandTLWIfPossible(tlw: QW.QWidget, frame_key,
                        desired_size_delta: QC.QSize):

    new_options = HG.client_controller.new_options

    (remember_size, remember_position, last_size, last_position,
     default_gravity, default_position, maximised,
     fullscreen) = new_options.GetFrameLocation(frame_key)

    if not tlw.isMaximized() and not tlw.isFullScreen():

        current_size = tlw.size()

        current_width = current_size.width()
        current_height = current_size.height()

        desired_delta_width = desired_size_delta.width()
        desired_delta_height = desired_size_delta.height()

        desired_width = current_width

        if desired_delta_width > 0:

            desired_width = current_width + desired_delta_width + FUZZY_PADDING

        desired_height = current_height

        if desired_delta_height > 0:

            desired_height = current_height + desired_delta_height + FUZZY_PADDING

        desired_size = QC.QSize(desired_width, desired_height)

        new_size = GetSafeSize(tlw, desired_size, default_gravity)

        if new_size.width() > current_width or new_size.height(
        ) > current_height:

            tlw.resize(new_size)

            #tlw.setMinimumSize( tlw.sizeHint() )

            SlideOffScreenTLWUpAndLeft(tlw)
Пример #10
0
class WebcamFeedWidget(MWB, QWidget):
    def __init__(self, params):
        MWB.__init__(self, params)
        QWidget.__init__(self)

    
        self.video_size = QSize(400, 300)
        self.timer = QTimer(self)
        self.capture = None

        self.image_label = QLabel()
        self.image_label.setFixedSize(self.video_size)

        self.main_layout = QVBoxLayout()
        self.main_layout.addWidget(self.image_label)
        self.setLayout(self.main_layout)

        self.setup_camera()

        self.resize(self.video_size)

    def setup_camera(self):
        self.capture = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
        self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, self.video_size.width())
        self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, self.video_size.height())

        self.timer.timeout.connect(self.display_video_stream)
        self.timer.start(20)

    def display_video_stream(self):
        _, frame = self.capture.read()
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        # frame = cv2.flip(frame, 1)
        image = QImage(frame, frame.shape[1], frame.shape[0],
                       frame.strides[0], QImage.Format_RGB888)
        scaled_image = image.scaled(self.video_size)
        self.image_label.setPixmap(QPixmap.fromImage(scaled_image))

        self.node.video_picture_updated(frame)
    
    def remove_event(self):
        self.timer.stop()
Пример #11
0
    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.

        At PyDMSymbolEditor this method handles the image preview.

        Parameters
        ----------
        event : QPaintEvent
        """
        if not self.preview:
            return
        size = QSize(140, 140)
        _painter = QPainter()
        _painter.begin(self)
        opt = QStyleOption()
        opt.initFrom(self)
        self.style().drawPrimitive(QStyle.PE_Widget, opt, _painter, self)
        image_to_draw = self.preview_file
        if isinstance(image_to_draw, QPixmap):
            w = float(image_to_draw.width())
            h = float(image_to_draw.height())
            sf = min(size.width() / w, size.height() / h)
            scale = (sf, sf)
            _painter.scale(scale[0], scale[1])
            _painter.drawPixmap(335 / sf, 120 / sf, image_to_draw)
        elif isinstance(image_to_draw, QSvgRenderer):
            draw_size = QSizeF(image_to_draw.defaultSize())
            draw_size.scale(QSizeF(size), Qt.KeepAspectRatio)
            image_to_draw.render(
                _painter,
                QRectF(335, 120, draw_size.width(), draw_size.height()))
        _painter.end()
        self.preview = False
Пример #12
0
    def _GetNumPyImage(self, clip_rect: QC.QRect, target_resolution: QC.QSize):

        if self._numpy_image is None:

            return numpy.zeros(
                (target_resolution.height(), target_resolution.width()),
                dtype='uint8')

        clip_size = clip_rect.size()
        clip_width = clip_size.width()
        clip_height = clip_size.height()

        (my_width, my_height) = self._resolution

        my_full_rect = QC.QRect(0, 0, my_width, my_height)

        ZERO_MARGIN = QC.QMargins(0, 0, 0, 0)

        clip_padding = ZERO_MARGIN
        target_padding = ZERO_MARGIN

        if clip_rect == my_full_rect:

            # full image

            source = self._numpy_image

        else:

            if target_resolution.width() > clip_width:

                # this is a tile that is being scaled up!
                # to reduce tiling artifacts (disagreement at otherwise good borders), we want to oversample the clip for our tile so lanczos and friends can get good neighbour data and then crop it
                # therefore, we'll figure out some padding for the clip, and then calculate what that means in the target end, and do a crop at the end

                # we want to pad. that means getting a larger resolution and keeping a record of the padding
                # can't pad if we are at 0 for x or y, or up against width/height max, but no problem in that case obviously

                # there is the float-int precision calculation problem again. we can't pick a padding of 3 in the clip if we are zooming by 150%--what do we clip off in the target: 4 or 5 pixels? whatever, we get warping
                # first let's figure a decent zoom estimate:

                zoom_estimate = target_resolution.width(
                ) / clip_width if target_resolution.width(
                ) > target_resolution.height(
                ) else target_resolution.height() / clip_height

                # now, if zoom is 150% (as a fraction, 3/2), we want a padding at the target of something that divides by 3 cleanly, or, since we are choosing at the clip in this case and will be multiplying, something that divides cleanly to 67%

                zoom_estimate_for_clip_padding_multiplier = 1 / zoom_estimate

                # and we want a nice padding size limit, big enough to make clean numbers but not so big that we are rendering the 8 tiles in a square around the one we want
                no_bigger_than = max(4, (clip_width + clip_height) // 4)

                nice_number = HydrusData.GetNicelyDivisibleNumberForZoom(
                    zoom_estimate_for_clip_padding_multiplier, no_bigger_than)

                if nice_number != -1:

                    # lanczos, I think, uses 4x4 neighbour grid to render. we'll say padding of 4 pixels to be safe for now, although 2 or 3 is probably correct???
                    # however it works, numbers these small are not a big deal

                    while nice_number < 4:

                        nice_number *= 2

                    PADDING_AMOUNT = nice_number

                    # LIMITATION: There is still a problem here for the bottom and rightmost edges. These tiles are not squares, so the shorter/thinner dimension my be an unpleasant number and be warped _anyway_, regardless of nice padding
                    # perhaps there is a way to boost left or top padding so we are rendering a full square tile but still cropping our target at the end, but with a little less warping
                    # I played around with this idea but did not have much success

                    LEFT_PADDING_AMOUNT = PADDING_AMOUNT
                    TOP_PADDING_AMOUNT = PADDING_AMOUNT

                    left_padding = min(LEFT_PADDING_AMOUNT, clip_rect.x())
                    top_padding = min(TOP_PADDING_AMOUNT, clip_rect.y())
                    right_padding = min(PADDING_AMOUNT, (my_width - 1) -
                                        clip_rect.bottomRight().x())
                    bottom_padding = min(PADDING_AMOUNT, (my_height - 1) -
                                         clip_rect.bottomRight().y())

                    clip_padding = QC.QMargins(left_padding, top_padding,
                                               right_padding, bottom_padding)

                    target_padding = clip_padding * zoom_estimate

            clip_rect_with_padding = clip_rect + clip_padding

            (x, y, clip_width, clip_height) = (clip_rect_with_padding.x(),
                                               clip_rect_with_padding.y(),
                                               clip_rect_with_padding.width(),
                                               clip_rect_with_padding.height())

            source = self._numpy_image[y:y + clip_height, x:x + clip_width]

        if target_resolution == clip_size:

            # 100% zoom

            result = source

        else:

            if clip_padding == ZERO_MARGIN:

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_resolution.width(), target_resolution.height()))

            else:

                target_width_with_padding = target_resolution.width(
                ) + target_padding.left() + target_padding.right()
                target_height_with_padding = target_resolution.height(
                ) + target_padding.top() + target_padding.bottom()

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_width_with_padding, target_height_with_padding))

                y = target_padding.top()
                x = target_padding.left()

                result = result[y:y + target_resolution.height(),
                                x:x + target_resolution.width()]

        if not result.data.c_contiguous:

            result = result.copy()

        return result
Пример #13
0
class OpenCVWidget(QLabel):
    def __init__(self, parent=None):
        super(OpenCVWidget, self).__init__(parent)

        self.video_size = QSize(320, 240)

        self.setAttribute(Qt.WA_OpaquePaintEvent, True)

        if not IN_DESIGNER:
            self._enable_edge = False

            self._video_device = '/dev/video0'
            self._edge_min_threshold = 190
            self._edge_max_threshold = 200

            self._enable_crosshairs = True

            self._line_color = (255, 127, 0)  # R G B

            self._line_thickness = 1

            self._h_lines = 0
            self._v_lines = 0
            self._c_radius = 25

            self.setup_camera()

    # Video

    def setup_camera(self):
        """Initialize camera.
        """

        self.capture = cv2.VideoCapture(self._video_device)

        w = self.capture.get(cv2.CAP_PROP_FRAME_WIDTH)
        h = self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT)

        self.video_size = QSize(w, h)

        self.setScaledContents(True)
        self.setMinimumSize(w, h)

        self.timer = QTimer()
        self.timer.timeout.connect(self.display_video_stream)
        self.timer.start(30)

    def minimumSizeHint(self):
        return self.video_size

    def timerEvent(self, QTimerEvent):
        print("hello")

    def display_video_stream(self):
        """Read frame from camera and repaint QLabel widget.
        """

        if self.capture.isOpened():

            result, frame = self.capture.read()

            if result is True:

                if self._enable_edge is True:
                    frame = cv2.Canny(frame, self._edge_min_threshold,
                                      self._edge_max_threshold)

                    if self._enable_crosshairs is True:
                        self.draw_crosshairs(frame)

                    image = QImage(frame.data, self.video_size.width(),
                                   self.video_size.height(),
                                   QImage.Format_Indexed8)

                else:
                    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    frame = cv2.flip(frame, 1)

                    if self._enable_crosshairs is True:
                        self.draw_crosshairs(frame)

                    image = QImage(frame, frame.shape[1], frame.shape[0],
                                   frame.strides[0], QImage.Format_RGB888)

                self.setPixmap(QPixmap.fromImage(image))

    # Helpers

    def draw_crosshairs(self, frame):

        w = self.video_size.width()
        h = self.video_size.height()

        cv2.line(frame, ((w / 2) + self._v_lines, 0),
                 ((w / 2) + self._v_lines, h), self._line_color,
                 self._line_thickness)

        cv2.line(frame, (0, (h / 2) - self._h_lines),
                 (w, (h / 2) - self._h_lines), self._line_color,
                 self._line_thickness)

        if self._c_radius > 1:
            cv2.circle(frame,
                       ((w / 2) + self._v_lines, (h / 2) - self._h_lines),
                       self._c_radius, self._line_color, self._line_thickness)

    # Slots

    @Slot(int)
    def setHorizontalLine(self, value):
        self._h_lines = value

    @Slot(int)
    def setVerticalLine(self, value):
        self._v_lines = value

    @Slot(int)
    def setCenterRadius(self, value):
        self._c_radius = value

    @Slot(bool)
    def enableCrosshairs(self, enabled):
        self._enable_crosshairs = enabled

    @Slot(bool)
    def enableEdge(self, enabled):
        self._enable_edge = enabled

    @Slot(int)
    def setEdgeMinThreshold(self, value):
        self._edge_min_threshold = value

    @Slot(int)
    def setEdgeMaxThreshold(self, value):
        self._edge_max_threshold = value

    @Slot(str)
    def setVideoDevice(self, path):
        self._video_device = path
Пример #14
0
class _QtMainWindow(QMainWindow):
    # This was added so that someone can patch
    # `napari._qt.qt_main_window._QtMainWindow._window_icon`
    # to their desired window icon
    _window_icon = NAPARI_ICON_PATH

    # To track window instances and facilitate getting the "active" viewer...
    # We use this instead of QApplication.activeWindow for compatibility with
    # IPython usage. When you activate IPython, it will appear that there are
    # *no* active windows, so we want to track the most recently active windows
    _instances: ClassVar[List['_QtMainWindow']] = []

    def __init__(self, qt_viewer: QtViewer, parent=None) -> None:
        super().__init__(parent)
        self.qt_viewer = qt_viewer

        self._quit_app = False
        self.setWindowIcon(QIcon(self._window_icon))
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setUnifiedTitleAndToolBarOnMac(True)
        center = QWidget(self)
        center.setLayout(QHBoxLayout())
        center.layout().addWidget(qt_viewer)
        center.layout().setContentsMargins(4, 0, 4, 0)
        self.setCentralWidget(center)

        self.setWindowTitle(qt_viewer.viewer.title)

        self._maximized_flag = False
        self._preferences_dialog = None
        self._preferences_dialog_size = QSize()
        self._status_bar = self.statusBar()

        # set SETTINGS plugin defaults.
        SETTINGS._defaults['plugins'].call_order = plugin_manager.call_order()

        # set the values in plugins to match the ones saved in SETTINGS
        if SETTINGS.plugins.call_order is not None:
            plugin_manager.set_call_order(SETTINGS.plugins.call_order)

        _QtMainWindow._instances.append(self)

        # Connect the notification dispacther to correctly propagate
        # notifications from threads. See: `napari._qt.qt_event_loop::get_app`
        application_instance = QApplication.instance()
        if application_instance:
            application_instance._dispatcher.sig_notified.connect(
                self.show_notification)

    @classmethod
    def current(cls):
        return cls._instances[-1] if cls._instances else None

    def event(self, e):
        if e.type() == QEvent.Close:
            # when we close the MainWindow, remove it from the instances list
            try:
                _QtMainWindow._instances.remove(self)
            except ValueError:
                pass
        if e.type() in {QEvent.WindowActivate, QEvent.ZOrderChange}:
            # upon activation or raise_, put window at the end of _instances
            try:
                inst = _QtMainWindow._instances
                inst.append(inst.pop(inst.index(self)))
            except ValueError:
                pass
        return super().event(e)

    def _load_window_settings(self):
        """
        Load window layout settings from configuration.
        """
        window_size = SETTINGS.application.window_size
        window_state = SETTINGS.application.window_state
        preferences_dialog_size = SETTINGS.application.preferences_size
        window_position = SETTINGS.application.window_position

        # It's necessary to verify if the window/position value is valid with the current screen.
        width, height = window_position
        screen_shape = QApplication.desktop().geometry()
        current_width = screen_shape.width()
        current_height = screen_shape.height()
        if current_width < width or current_height < height:
            window_position = (self.x(), self.y())

        window_maximized = SETTINGS.application.window_maximized
        window_fullscreen = SETTINGS.application.window_fullscreen
        return (
            window_state,
            window_size,
            window_position,
            window_maximized,
            window_fullscreen,
            preferences_dialog_size,
        )

    def _get_window_settings(self):
        """
        Return current window settings.

        Symmetric to the 'set_window_settings' setter.
        """
        window_size = (self.width(), self.height())
        window_fullscreen = self.isFullScreen()

        if window_fullscreen:
            window_maximized = self._maximized_flag
        else:
            window_maximized = self.isMaximized()

        window_position = (self.x(), self.y())
        preferences_dialog_size = (
            self._preferences_dialog_size.width(),
            self._preferences_dialog_size.height(),
        )
        window_state = qbytearray_to_str(self.saveState())
        return (
            window_state,
            window_size,
            window_position,
            window_maximized,
            window_fullscreen,
            preferences_dialog_size,
        )

    def _set_window_settings(
        self,
        window_state,
        window_size,
        window_position,
        window_maximized,
        window_fullscreen,
        preferences_dialog_size,
    ):
        """
        Set window settings.

        Symmetric to the 'get_window_settings' accessor.
        """
        self.setUpdatesEnabled(False)
        self.setWindowState(Qt.WindowNoState)

        if preferences_dialog_size:
            self._preferences_dialog_size = QSize(*preferences_dialog_size)

        if window_position:
            window_position = QPoint(*window_position)
            self.move(window_position)

        if window_size:
            window_size = QSize(*window_size)
            self.resize(window_size)

        if window_state:
            self.restoreState(str_to_qbytearray(window_state))

        if window_fullscreen:
            self.setWindowState(Qt.WindowFullScreen)
            self._maximized_flag = window_maximized
        elif window_maximized:
            self.setWindowState(Qt.WindowMaximized)

        self.setUpdatesEnabled(True)

    def _save_current_window_settings(self):
        """Save the current geometry of the main window."""
        (
            window_state,
            window_size,
            window_position,
            window_maximized,
            window_fullscreen,
            preferences_dialog_size,
        ) = self._get_window_settings()

        if SETTINGS.application.save_window_geometry:
            SETTINGS.application.window_maximized = window_maximized
            SETTINGS.application.window_fullscreen = window_fullscreen
            SETTINGS.application.window_position = window_position
            SETTINGS.application.window_size = window_size
            SETTINGS.application.window_statusbar = (
                not self._status_bar.isHidden())
            SETTINGS.application.preferences_size = preferences_dialog_size

        if SETTINGS.application.save_window_state:
            SETTINGS.application.window_state = window_state

    def _update_preferences_dialog_size(self, size):
        """Save preferences dialog size."""
        self._preferences_dialog_size = size

    def close(self, quit_app=False):
        """Override to handle closing app or just the window."""
        self._quit_app = quit_app
        return super().close()

    def close_window(self):
        """Close active dialog or active window."""
        parent = QApplication.focusWidget()
        while parent is not None:
            if isinstance(parent, QMainWindow):
                self.close()
                break

            if isinstance(parent, QDialog):
                parent.close()
                break

            parent = parent.parent()

    def closeEvent(self, event):
        """This method will be called when the main window is closing.

        Regardless of whether cmd Q, cmd W, or the close button is used...
        """
        # Close any floating dockwidgets
        for dock in self.findChildren(QtViewerDockWidget):
            if dock.isFloating():
                dock.setFloating(False)

        self._save_current_window_settings()

        # On some versions of Darwin, exiting while fullscreen seems to tickle
        # some bug deep in NSWindow.  This forces the fullscreen keybinding
        # test to complete its draw cycle, then pop back out of fullscreen.
        if self.isFullScreen():
            self.showNormal()
            for _i in range(5):
                time.sleep(0.1)
                QApplication.processEvents()

        if self._quit_app:
            quit_app()

        event.accept()

    def restart(self):
        """Restart the napari application in a detached process."""
        process = QProcess()
        process.setProgram(sys.executable)

        if not running_as_bundled_app():
            process.setArguments(sys.argv)

        process.startDetached()
        self.close(quit_app=True)

    @staticmethod
    @Slot(Notification)
    def show_notification(notification: Notification):
        """Show notification coming from a thread."""
        NapariQtNotification.show_notification(notification)
Пример #15
0
 def _save_size(sz: QSize):
     app_pref.preferences_size = (sz.width(), sz.height())
Пример #16
0
    def _GetNumPyImage(self, clip_rect: QC.QRect, target_resolution: QC.QSize):

        clip_size = clip_rect.size()

        (my_width, my_height) = self._resolution

        my_full_rect = QC.QRect(0, 0, my_width, my_height)

        ZERO_MARGIN = QC.QMargins(0, 0, 0, 0)

        clip_padding = ZERO_MARGIN
        target_padding = ZERO_MARGIN

        if clip_rect == my_full_rect:

            # full image

            source = self._numpy_image

        else:

            if target_resolution.width() > clip_size.width():

                # this is a tile that is being scaled!
                # to reduce tiling artifacts, we want to oversample the clip for our tile so lanczos and friends can get good neighbour data and then crop it
                # therefore, we'll figure out some padding for the clip, and then calculate what that means in the target end, and do a crop at the end

                # we want to pad. that means getting a larger resolution and keeping a record of the padding
                # can't pad if we are at 0 for x or y, or up against width/height max
                # but if we can pad, we will get a larger clip size and then _clip_ a better target endpoint. this is tricky.

                PADDING_AMOUNT = 4

                left_padding = min(PADDING_AMOUNT, clip_rect.x())
                top_padding = min(PADDING_AMOUNT, clip_rect.y())
                right_padding = min(PADDING_AMOUNT,
                                    my_width - clip_rect.bottomRight().x())
                bottom_padding = min(PADDING_AMOUNT,
                                     my_height - clip_rect.bottomRight().y())

                clip_padding = QC.QMargins(left_padding, top_padding,
                                           right_padding, bottom_padding)

                # this is ugly and super inaccurate
                target_padding = clip_padding * (target_resolution.width() /
                                                 clip_size.width())

            clip_rect_with_padding = clip_rect + clip_padding

            (x, y, clip_width, clip_height) = (clip_rect_with_padding.x(),
                                               clip_rect_with_padding.y(),
                                               clip_rect_with_padding.width(),
                                               clip_rect_with_padding.height())

            source = self._numpy_image[y:y + clip_height, x:x + clip_width]

        if target_resolution == clip_size:

            # 100% zoom

            result = source

        else:

            if clip_padding == ZERO_MARGIN:

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_resolution.width(), target_resolution.height()))

            else:

                target_width_with_padding = target_resolution.width(
                ) + target_padding.left() + target_padding.right()
                target_height_with_padding = target_resolution.height(
                ) + target_padding.top() + target_padding.bottom()

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_width_with_padding, target_height_with_padding))

                y = target_padding.top()
                x = target_padding.left()

                result = result[y:y + target_resolution.height(),
                                x:x + target_resolution.width()]

        if not result.data.c_contiguous:

            result = result.copy()

        return result
Пример #17
0
def GetSafeSize(tlw: QW.QWidget, min_size: QC.QSize, gravity) -> QC.QSize:

    min_width = min_size.width()
    min_height = min_size.height()

    frame_padding = tlw.frameGeometry().size() - tlw.size()

    parent = tlw.parentWidget()

    if parent is None:

        width = min_width
        height = min_height

    else:

        parent_window = parent.window()

        # when we initialise, we might not have a frame yet because we haven't done show() yet
        # so borrow main gui's
        if frame_padding.isEmpty():

            main_gui = HG.client_controller.gui

            if main_gui is not None and QP.isValid(
                    main_gui) and not main_gui.isFullScreen():

                frame_padding = main_gui.frameGeometry().size(
                ) - main_gui.size()

        if parent_window.isFullScreen():

            parent_available_size = parent_window.size()

        else:

            parent_frame_size = parent_window.frameGeometry().size()

            parent_available_size = parent_frame_size - frame_padding

        parent_available_width = parent_available_size.width()
        parent_available_height = parent_available_size.height()

        (width_gravity, height_gravity) = gravity

        if width_gravity == -1:

            width = min_width

        else:

            max_width = parent_available_width - (2 * CHILD_POSITION_PADDING)

            width = int(width_gravity * max_width)

        if height_gravity == -1:

            height = min_height

        else:

            max_height = parent_available_height - (2 * CHILD_POSITION_PADDING)

            height = int(height_gravity * max_height)

    display_size = GetDisplaySize(tlw)

    display_available_size = display_size - frame_padding

    width = min(display_available_size.width() - 2 * CHILD_POSITION_PADDING,
                width)
    height = min(display_available_size.height() - 2 * CHILD_POSITION_PADDING,
                 height)

    return QC.QSize(width, height)
Пример #18
0
class _QtMainWindow(QMainWindow):
    # This was added so that someone can patch
    # `napari._qt.qt_main_window._QtMainWindow._window_icon`
    # to their desired window icon
    _window_icon = NAPARI_ICON_PATH

    def __init__(self, parent=None) -> None:
        super().__init__(parent)

        self._quit_app = False
        self.setWindowIcon(QIcon(self._window_icon))
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setUnifiedTitleAndToolBarOnMac(True)
        center = QWidget(self)
        center.setLayout(QHBoxLayout())
        center.layout().setContentsMargins(4, 0, 4, 0)
        self.setCentralWidget(center)

        self._maximized_flag = False
        self._preferences_dialog_size = QSize()
        self._status_bar = self.statusBar()

    def _load_window_settings(self):
        """
        Load window layout settings from configuration.
        """
        window_size = SETTINGS.application.window_size
        window_state = SETTINGS.application.window_state
        preferences_dialog_size = SETTINGS.application.preferences_size
        window_position = SETTINGS.application.window_position

        # It's necessary to verify if the window/position value is valid with the current screen.
        width, height = window_position
        screen_shape = QApplication.desktop().geometry()
        current_width = screen_shape.width()
        current_height = screen_shape.height()
        if current_width < width or current_height < height:
            window_position = (self.x(), self.y())

        window_maximized = SETTINGS.application.window_maximized
        window_fullscreen = SETTINGS.application.window_fullscreen
        return (
            window_state,
            window_size,
            window_position,
            window_maximized,
            window_fullscreen,
            preferences_dialog_size,
        )

    def _get_window_settings(self):
        """
        Return current window settings.

        Symmetric to the 'set_window_settings' setter.
        """
        window_size = (self.width(), self.height())
        window_fullscreen = self.isFullScreen()

        if window_fullscreen:
            window_maximized = self._maximized_flag
        else:
            window_maximized = self.isMaximized()

        window_position = (self.x(), self.y())
        preferences_dialog_size = (
            self._preferences_dialog_size.width(),
            self._preferences_dialog_size.height(),
        )
        window_state = qbytearray_to_str(self.saveState())
        return (
            window_state,
            window_size,
            window_position,
            window_maximized,
            window_fullscreen,
            preferences_dialog_size,
        )

    def _set_window_settings(
        self,
        window_state,
        window_size,
        window_position,
        window_maximized,
        window_fullscreen,
        preferences_dialog_size,
    ):
        """
        Set window settings.

        Symmetric to the 'get_window_settings' accessor.
        """
        self.setUpdatesEnabled(False)
        self.setWindowState(Qt.WindowNoState)

        if preferences_dialog_size:
            self._preferences_dialog_size = QSize(*preferences_dialog_size)

        if window_position:
            window_position = QPoint(*window_position)
            self.move(window_position)

        if window_size:
            window_size = QSize(*window_size)
            self.resize(window_size)

        if window_state:
            self.restoreState(str_to_qbytearray(window_state))

        if window_fullscreen:
            self.setWindowState(Qt.WindowFullScreen)
            self._maximized_flag = window_maximized
        elif window_maximized:
            self.setWindowState(Qt.WindowMaximized)

        self.setUpdatesEnabled(True)

    def _save_current_window_settings(self):
        """Save the current geometry of the main window."""
        (
            window_state,
            window_size,
            window_position,
            window_maximized,
            window_fullscreen,
            preferences_dialog_size,
        ) = self._get_window_settings()

        SETTINGS.application.window_size = window_size
        SETTINGS.application.window_maximized = window_maximized
        SETTINGS.application.window_fullscreen = window_fullscreen
        SETTINGS.application.window_position = window_position
        SETTINGS.application.window_state = window_state
        SETTINGS.application.preferences_size = preferences_dialog_size
        SETTINGS.application.window_statusbar = not self._status_bar.isHidden()

    def _update_preferences_dialog_size(self, event):
        """Save preferences dialog size."""
        self._preferences_dialog_size = event.size()

    def close(self, quit_app=False):
        """Override to handle closing app or just the window."""
        self._quit_app = quit_app
        return super().close()

    def closeEvent(self, event):
        """This method will be called when the main window is closing.

        Regardless of whether cmd Q, cmd W, or the close button is used...
        """
        # Close any floating dockwidgets
        for dock in self.findChildren(QtViewerDockWidget):
            if dock.isFloating():
                dock.setFloating(False)

        self._save_current_window_settings()

        # On some versions of Darwin, exiting while fullscreen seems to tickle
        # some bug deep in NSWindow.  This forces the fullscreen keybinding
        # test to complete its draw cycle, then pop back out of fullscreen.
        if self.isFullScreen():
            self.showNormal()
            for _i in range(5):
                time.sleep(0.1)
                QApplication.processEvents()

        if self._quit_app:
            quit_app()

        event.accept()
Пример #19
0
class RealizationDelegate(QStyledItemDelegate):
    def __init__(self, width, height, parent=None) -> None:
        super(RealizationDelegate, self).__init__(parent)
        self._size = QSize(width, height)

    def paint(self, painter, option: QStyleOptionViewItem, index: QModelIndex) -> None:

        text = index.data(RealLabelHint)
        colors = index.data(RealJobColorHint)

        painter.save()
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)

        border_pen = QPen()
        border_pen.setColor(QColorConstants.Black)
        border_pen.setWidth(1)

        if option.state & QStyle.State_Selected:

            # selection outline
            select_color = QColorConstants.Blue
            painter.setBrush(select_color)
            painter.setPen(border_pen)
            painter.drawRect(option.rect)

            # job status
            margin = 5
            rect = QRect(
                option.rect.x() + margin,
                option.rect.y() + margin,
                option.rect.width() - (margin * 2),
                option.rect.height() - (margin * 2),
            )
            painter.fillRect(rect, index.data(RealStatusColorHint))

            self._paint_inner_grid(painter, option.rect, colors)

            text_pen = QPen()
            text_pen.setColor(select_color)
            painter.setPen(text_pen)
            painter.drawText(option.rect, Qt.AlignCenter, text)

        else:
            # # job status
            painter.setBrush(index.data(RealStatusColorHint))
            painter.setPen(border_pen)
            painter.drawRect(option.rect)

            self._paint_inner_grid(painter, option.rect, colors)

            text_pen = QPen()
            text_pen.setColor(QColorConstants.Black)
            painter.setPen(text_pen)
            painter.drawText(option.rect, Qt.AlignCenter, text)

        painter.restore()

    def _paint_inner_grid(self, painter: QPainter, rect: QRect, colors) -> None:
        margin = 10
        inner_grid_w = self._size.width() - (margin * 2)
        inner_grid_h = self._size.height() - (margin * 2)
        inner_grid_x = rect.x() + margin
        inner_grid_y = rect.y() + margin
        job_nr = len(colors)
        grid_dim = math.ceil(math.sqrt(job_nr))
        w = math.ceil(inner_grid_w / grid_dim)
        h = math.ceil(inner_grid_h / grid_dim)
        k = 0
        for y in range(grid_dim):
            for x in range(grid_dim):
                x_pos = inner_grid_x + (x * w)
                y_pos = inner_grid_y + (y * h)
                rect = QRect(x_pos, y_pos, w, h)
                if k >= job_nr:
                    color = QColorConstants.Gray
                else:
                    color = colors[k]
                painter.fillRect(rect, color)
                k += 1

    def sizeHint(self, option, index) -> QSize:
        return self._size
Пример #20
0
class FileView(QAbstractItemView):
    def __init__(self, parent=None):
        super(FileView, self).__init__(parent)
        self.setSelectionMode(self.NoSelection)
        self._line_offsets = [0]
        self._line_sizes = []
        self._size = QSize()
        self._force_follow = False

        self._init_font()

    def paintEvent(self, event):
        painter = QPainter(self.viewport())

        view_rect = self._translate(event.rect())
        if view_rect.y() < 0:
            rect = QRect()
            rect.setHeight(self.viewport().height() + view_rect.y())
            rect.setWidth(self.viewport().width())

            brush = self.palette().brush(QPalette.Disabled, QPalette.Window)
            painter.fillRect(rect, brush)

        for index in self._intersecting_rows(view_rect):
            option = self._style_option(index)
            delegate = self.itemDelegate(index)
            delegate.paint(painter, option, index)

    def setSelection(self, _rect, _flags):
        """setSelection is a pure virtual member function of QAbstractItemView"""

    def scrollTo(self, _index, _hint):
        """scrollTo is a pure virtual member function of QAbstractItemView"""

    def indexAt(self, point):
        """indexAt is a pure virtual member function of QAbstractItemView"""
        return self.model().index(self._resolve_row(point), 0)

    def moveCursor(self, _action, _modifiers):
        """moveCursor is a pure virtual member function of QAbstractItemView"""
        return QModelIndex()

    def visualRect(self, index):
        """visualRect is a pure virtual member function of QAbstractItemView"""
        if index.row() < 0 or index.row() >= len(self._line_sizes):
            return QRect()
        point = QPoint(
            -self.horizontalOffset(),
            self._line_offsets[index.row()] - self.verticalOffset(),
        )
        return QRect(point, self._line_sizes[index.row()])

    def visualRegionForSelection(self, _selection):
        """visualRegionForSelection is a pure virtual member function of QAbstractItemView"""
        return QRegion()

    def horizontalOffset(self):
        """horizontalOffset is a pure virtual member function of QAbstractItemView"""
        return self.horizontalScrollBar().value()

    def verticalOffset(self):
        """verticalOffset is a pure virtual member function of QAbstractItemView"""
        if self._force_follow:
            return self._size.height() - self.viewport().height()
        else:
            return self.verticalScrollBar().value()

    def isIndexHidden(self, _index):
        """isIndexHidden is a pure virtual member function of QAbstractItemView"""
        return False

    @Slot(QModelIndex, int, int)
    def rowsInserted(self, parent, first, last):
        """rowsInserted is an overriden slot of QAbstractItemView"""
        if first != len(self._line_sizes):
            raise NotImplementedError("FileView can only be appended to")
        model = self.model()

        follow = (self._force_follow or self.verticalOffset()
                  == self.verticalScrollBar().maximum())

        for idx in range(first, last):
            end = self._size.height()
            index = model.index(idx, 0)

            option = self._style_option(index)
            delegate = self.itemDelegate(index)
            size = delegate.sizeHint(option, index)

            self._line_sizes.append(size)
            self._line_offsets.append(end + size.height())
            self._size.setWidth(max(size.width(), self._size.width()))
            self._size.setHeight(end + size.height())
        self.updateGeometries()

        if follow:
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().maximum())
        self.viewport().update()

    @Slot()
    def updateGeometries(self):
        """updateGeometries is an overridden slot of QAbstractItemView"""
        horizontal_max = self._size.width() - self.viewport().width()
        self.horizontalScrollBar().setRange(0, horizontal_max)

        if self._force_follow:
            self.verticalScrollBar().setRange(0, 0)
        else:
            vertical_max = self._size.height() - self.viewport().height()
            self.verticalScrollBar().setRange(0, vertical_max)

        QAbstractItemView.updateGeometries(self)

    @Slot(bool)
    def enable_follow_mode(self, follow=True):
        """Enables or disabled follow mode, as in tail -f"""
        self._force_follow = follow
        self.updateGeometries()
        self.verticalScrollBar().setValue(self.verticalScrollBar().maximum())
        self.viewport().update()

    def _intersecting_rows(self, rect):
        """Get rows that intersect with rect"""
        model = self.model()
        first = max(0, bisect_left(self._line_offsets, rect.top()) - 1)
        last = min(len(self._line_sizes),
                   bisect_right(self._line_offsets, rect.bottom()))

        return [model.index(row, 0) for row in range(first, last)]

    def _resolve_row(self, point):
        """Get row that is at point"""
        y = point.y() + self.verticalOffset()
        return max(0, bisect_left(self._line_offsets, y) - 1)

    def _init_font(self):
        # There isn't a standard way of getting the system default monospace
        # font in Qt4 (it was introduced in Qt5.2). If QFontDatabase.FixedFont
        # exists, then we can assume that this functionality exists and ask for
        # the correct font directly. Otherwise we ask for a font that doesn't
        # exist and specify our requirements. Qt then finds an existing font
        # that best matches our parameters.
        if hasattr(QFontDatabase, "systemFont") and hasattr(
                QFontDatabase, "FixedFont"):
            font = QFontDatabase.systemFont(QFontDatabase.FixedFont)
        else:
            font = QFont("")
            font.setFixedPitch(True)
            font.setStyleHint(QFont.Monospace)
        self.setFont(font)

    def _style_option(self, index):
        """Get default style option for index"""
        option = QStyleOptionViewItem()
        option.font = self.font()
        option.rect = self.visualRect(index)
        option.state = QStyle.State_Enabled
        return option

    def _translate(self, rect):
        """Translate rect from viewport to document coordinates"""
        return rect.translated(self.horizontalOffset(), self.verticalOffset())