class View(QWidget):
    def __init__(self, buffer, view_info):
        super(View, self).__init__()

        self.buffer = buffer

        # Init widget attributes.
        if get_emacs_func_result("eaf-emacs-not-use-reparent-technology", []):
            self.setWindowFlags(Qt.FramelessWindowHint
                                | Qt.WindowStaysOnTopHint
                                | Qt.NoDropShadowWindowHint)
        else:
            self.setWindowFlags(Qt.FramelessWindowHint)

        self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True)
        self.setContentsMargins(0, 0, 0, 0)
        self.installEventFilter(self)

        # Init attributes.
        self.view_info = view_info
        (self.buffer_id, self.emacs_xid, self.x, self.y, self.width,
         self.height) = view_info.split(":")
        self.x = int(self.x)
        self.y = int(self.y)
        self.width = int(self.width)
        self.height = int(self.height)

        # Build QGraphicsView.
        self.layout = QVBoxLayout(self)
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.graphics_view = QGraphicsView(buffer, self)

        # Remove border from QGraphicsView.
        self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setRenderHints(QPainter.Antialiasing
                                          | QPainter.SmoothPixmapTransform
                                          | QPainter.TextAntialiasing)
        self.graphics_view.setFrameStyle(QFrame.NoFrame)

        # Fill background color.
        self.graphics_view.setBackgroundBrush(QBrush(buffer.background_color))

        # Add graphics view.
        self.layout.addWidget(self.graphics_view)

        # NOTE: show function must start before resize to trigger *first* resizeEvent after show.
        self.show()

        # Resize after show to trigger fit view operation.
        self.resize(self.width, self.height)

        self.buffer.aspect_ratio_change.connect(self.adjust_aspect_ratio)

    def resizeEvent(self, event):
        # Fit content to view rect just when buffer fit_to_view option is enable.
        if self.buffer.fit_to_view:
            if event.oldSize().isValid():
                self.graphics_view.fitInView(
                    self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio)
                QWidget.resizeEvent(self, event)

    def adjust_aspect_ratio(self):
        widget_width = self.width
        widget_height = self.height

        if self.buffer.aspect_ratio == 0:
            self.buffer.buffer_widget.resize(self.width, self.height)

            self.layout.setContentsMargins(0, 0, 0, 0)
        else:
            view_height = widget_height * (
                1 - 2 * self.buffer.vertical_padding_ratio)
            view_width = view_height * self.buffer.aspect_ratio
            horizontal_padding = (widget_width - view_width) / 2
            vertical_padding = self.buffer.vertical_padding_ratio * widget_height

            self.buffer.buffer_widget.resize(view_width, view_height)

            self.layout.setContentsMargins(horizontal_padding,
                                           vertical_padding,
                                           horizontal_padding,
                                           vertical_padding)

    def eventFilter(self, obj, event):
        # import time
        # print(time.time(), event.type())

        if event.type() in [QEvent.ShortcutOverride]:
            eval_in_emacs('eaf-activate-emacs-window', [self.buffer_id])

        # Focus emacs buffer when user click view.
        event_type = [
            QEvent.MouseButtonPress, QEvent.MouseButtonRelease,
            QEvent.MouseButtonDblClick
        ]
        if platform.system() != "Darwin":
            event_type += [QEvent.Wheel]

        if event.type() in event_type:
            focus_emacs_buffer(self.buffer_id)
            # Stop mouse event.
            return True

        return False

    def showEvent(self, event):
        # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed.
        self.reparent()

        if platform.system() in ["Windows", "Darwin"]:
            eval_in_emacs('eaf-activate-emacs-window', [])

        # Make graphics view at left-top corner after show.
        self.graphics_view.verticalScrollBar().setValue(0)
        self.graphics_view.horizontalScrollBar().setValue(0)

    def reparent(self):
        # print("Reparent: ", self.buffer.url)
        qwindow = self.windowHandle()

        if not get_emacs_func_result("eaf-emacs-not-use-reparent-technology",
                                     []):
            qwindow.setParent(QWindow.fromWinId(int(self.emacs_xid)))

        qwindow.setPosition(QPoint(self.x, self.y))

    def try_show_top_view(self):
        if get_emacs_func_result("eaf-emacs-not-use-reparent-technology", []):
            self.setWindowFlag(Qt.WindowStaysOnTopHint, True)
            self.show()

    def try_hide_top_view(self):
        if get_emacs_func_result("eaf-emacs-not-use-reparent-technology", []):
            self.setWindowFlag(Qt.WindowStaysOnTopHint, False)
            self.hide()

    def destroy_view(self):
        # print("Destroy: ", self.buffer.url)
        self.destroy()
Example #2
0
class SlideViewer(QWidget):
    eventSignal = pyqtSignal(PyQt5.QtCore.QEvent)

    def __init__(self, parent: QWidget = None, viewer_top_else_left=True):
        super().__init__(parent)
        self.init_view()
        self.init_labels(word_wrap=viewer_top_else_left)
        self.init_layout(viewer_top_else_left)

    def init_view(self):
        self.scene = MyGraphicsScene()
        self.view = QGraphicsView()
        self.view.setScene(self.scene)
        self.view.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.view.viewport().installEventFilter(self)

        self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)
        self.mouse_press_view = QPoint()

        self.view.horizontalScrollBar().sliderMoved.connect(
            self.on_view_changed)
        self.view.verticalScrollBar().sliderMoved.connect(self.on_view_changed)
        self.scale_initializer_deffered_function = None
        self.slide_view_params = None
        self.slide_helper = None

    def init_labels(self, word_wrap):
        # word_wrap = True
        self.level_downsample_label = QLabel()
        self.level_downsample_label.setWordWrap(word_wrap)
        self.level_size_label = QLabel()
        self.level_size_label.setWordWrap(word_wrap)
        self.selected_rect_label = QLabel()
        self.selected_rect_label.setWordWrap(word_wrap)
        self.mouse_pos_scene_label = QLabel()
        self.mouse_pos_scene_label.setWordWrap(word_wrap)
        self.view_rect_scene_label = QLabel()
        self.view_rect_scene_label.setWordWrap(word_wrap)
        self.labels_layout = QVBoxLayout()
        self.labels_layout.setAlignment(Qt.AlignTop)
        self.labels_layout.addWidget(self.level_downsample_label)
        self.labels_layout.addWidget(self.level_size_label)
        self.labels_layout.addWidget(self.mouse_pos_scene_label)
        # self.labels_layout.addWidget(self.selected_rect_label)
        self.labels_layout.addWidget(self.view_rect_scene_label)

    def init_layout(self, viewer_top_else_left=True):
        main_layout = QVBoxLayout(
            self) if viewer_top_else_left else QHBoxLayout(self)
        main_layout.addWidget(self.view, )
        main_layout.addLayout(self.labels_layout)
        # main_layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(main_layout)

    """
    If you want to start view frome some point at some level, specify <level> and <level_rect> params. 
    level_rect : rect in dimensions of slide at level=level. If None - fits the whole size of slide
    """

    def load(self,
             slide_view_params: SlideViewParams,
             preffered_rects_count=2000,
             zoom_step=1.15):
        self.zoom_step = zoom_step
        self.slide_view_params = slide_view_params
        self.slide_helper = SlideHelper(slide_view_params.slide_path)

        self.slide_graphics = SlideGraphicsGroup(slide_view_params,
                                                 preffered_rects_count)
        self.scene.clear()
        self.scene.addItem(self.slide_graphics)

        if self.slide_view_params.level == -1 or self.slide_view_params.level is None:
            self.slide_view_params.level = self.slide_helper.get_max_level()

        self.slide_graphics.update_visible_level(self.slide_view_params.level)
        self.scene.setSceneRect(
            self.slide_helper.get_rect_for_level(self.slide_view_params.level))

        def scale_initializer_deffered_function():
            self.view.resetTransform()
            # print("size when loading: ", self.view.viewport().size())
            if self.slide_view_params.level_rect:
                # self.view.fitInView(QRectF(*self.slide_view_params.level_rect), Qt.KeepAspectRatioByExpanding)
                self.view.fitInView(QRectF(*self.slide_view_params.level_rect),
                                    Qt.KeepAspectRatio)
                # print("after fit: ", self.get_current_view_scene_rect())
            else:
                start_margins = QMarginsF(200, 200, 200, 200)
                start_image_rect_ = self.slide_helper.get_rect_for_level(
                    self.slide_view_params.level)
                self.view.fitInView(start_image_rect_ + start_margins,
                                    Qt.KeepAspectRatio)

        self.scale_initializer_deffered_function = scale_initializer_deffered_function

    def eventFilter(self, qobj: 'QObject', event: QEvent):
        self.eventSignal.emit(event)
        event_processed = False
        # print("size when event: ", event, event.type(), self.view.viewport().size())
        if isinstance(event, QShowEvent):
            """
            we need it deffered because fitInView logic depends on current viewport size. Expecting at this point widget is finally resized before being shown at first
            """
            if self.scale_initializer_deffered_function:
                # TODO labels start to occupy some space after view was already fitted, and labels will reduce size of viewport
                # self.update_labels()
                self.scale_initializer_deffered_function()
                self.on_view_changed()
                self.scale_initializer_deffered_function = None
        elif isinstance(event, QWheelEvent):
            event_processed = self.process_viewport_wheel_event(event)
            # we handle wheel event to prevent GraphicsView interpret it as scrolling
        elif isinstance(event, QMouseEvent):
            event_processed = self.process_mouse_event(event)

        return event_processed

    def process_viewport_wheel_event(self, event: QWheelEvent):
        # print("size when wheeling: ", self.view.viewport().size())
        zoom_in = self.zoom_step
        zoom_out = 1 / zoom_in
        zoom_ = zoom_in if event.angleDelta().y() > 0 else zoom_out
        self.update_scale(event.pos(), zoom_)
        event.accept()
        self.on_view_changed()
        return True

    def process_mouse_event(self, event: QMouseEvent):
        if self.slide_helper is None:
            return False

        if event.button() == Qt.MiddleButton:
            if event.type() == QEvent.MouseButtonPress:
                self.slide_graphics.update_grid_visibility(
                    not self.slide_graphics.slide_view_params.grid_visible)
                # items=self.scene.items()
                # QMessageBox.information(None, "Items", str(items))
                return True
            # self.update_scale(QPoint(), 1.15)
        elif event.button() == Qt.LeftButton:
            if event.type() == QEvent.MouseButtonPress:
                self.mouse_press_view = QPoint(event.pos())
                self.rubber_band.setGeometry(
                    QRect(self.mouse_press_view, QSize()))
                self.rubber_band.show()
                return True
            elif event.type() == QEvent.MouseButtonRelease:
                self.rubber_band.hide()
                self.remember_selected_rect_params()
                self.slide_graphics.update_selected_rect_0_level(
                    self.slide_view_params.selected_rect_0_level)
                self.update_labels()
                self.scene.invalidate()
                return True
        elif event.type() == QEvent.MouseMove:
            self.mouse_pos_scene_label.setText(
                "mouse_scene: " +
                point_to_str(self.view.mapToScene(event.pos())))
            if not self.mouse_press_view.isNull():
                self.rubber_band.setGeometry(
                    QRect(self.mouse_press_view, event.pos()).normalized())
            return True

        return False

    def remember_selected_rect_params(self):
        pos_scene = self.view.mapToScene(self.rubber_band.pos())
        rect_scene = self.view.mapToScene(
            self.rubber_band.rect()).boundingRect()
        downsample = self.slide_helper.get_downsample_for_level(
            self.slide_view_params.level)
        selected_qrectf_0_level = QRectF(pos_scene * downsample,
                                         rect_scene.size() * downsample)
        self.slide_view_params.selected_rect_0_level = selected_qrectf_0_level.getRect(
        )

    def update_scale(self, mouse_pos: QPoint, zoom):
        old_mouse_pos_scene = self.view.mapToScene(mouse_pos)
        old_view_scene_rect = self.view.mapToScene(
            self.view.viewport().rect()).boundingRect()

        old_level = self.get_best_level_for_scale(
            self.get_current_view_scale())
        old_level_downsample = self.slide_helper.get_downsample_for_level(
            old_level)
        new_level = self.get_best_level_for_scale(
            self.get_current_view_scale() * zoom)
        new_level_downsample = self.slide_helper.get_downsample_for_level(
            new_level)

        level_scale_delta = 1 / (new_level_downsample / old_level_downsample)

        r = old_view_scene_rect.topLeft()
        m = old_mouse_pos_scene
        new_view_scene_rect_top_left = (m - (m - r) / zoom) * level_scale_delta
        new_view_scene_rect = QRectF(
            new_view_scene_rect_top_left,
            old_view_scene_rect.size() * level_scale_delta / zoom)

        new_scale = self.get_current_view_scale(
        ) * zoom * new_level_downsample / old_level_downsample
        transform = QTransform().scale(new_scale, new_scale).translate(
            -new_view_scene_rect.x(), -new_view_scene_rect.y())

        new_rect = self.slide_helper.get_rect_for_level(new_level)
        self.scene.setSceneRect(new_rect)
        self.slide_view_params.level = new_level
        self.reset_view_transform()
        self.view.setTransform(transform, False)
        self.slide_graphics.update_visible_level(new_level)
        self.update_labels()

    def get_best_level_for_scale(self, scale):
        scene_width = self.scene.sceneRect().size().width()
        candidates = [0]
        for level in self.slide_helper.get_levels():
            w, h = self.slide_helper.get_level_size(level)
            if scene_width * scale <= w:
                candidates.append(level)
        best_level = max(candidates)
        return best_level

    def update_labels(self):
        level_downsample = self.slide_helper.get_downsample_for_level(
            self.slide_view_params.level)
        level_size = self.slide_helper.get_level_size(
            self.slide_view_params.level)
        self.level_downsample_label.setText(
            "level, downsample: {}, {:.0f}".format(
                self.slide_view_params.level, level_downsample))
        self.level_size_label.setText(
            "level_size: ({}, {})".format(*level_size))
        self.view_rect_scene_label.setText(
            "view_scene: ({:.0f},{:.0f},{:.0f},{:.0f})".format(
                *self.get_current_view_scene_rect().getRect()))
        if self.slide_view_params.selected_rect_0_level:
            self.selected_rect_label.setText(
                "selected rect (0-level): ({:.0f},{:.0f},{:.0f},{:.0f})".
                format(*self.slide_view_params.selected_rect_0_level))

    def on_view_changed(self):
        if self.scale_initializer_deffered_function is None and self.slide_view_params:
            self.slide_view_params.level_rect = self.get_current_view_scene_rect(
            ).getRect()
        self.update_labels()

    def reset_view_transform(self):
        self.view.resetTransform()
        self.view.horizontalScrollBar().setValue(0)
        self.view.verticalScrollBar().setValue(0)

    def get_current_view_scene_rect(self):
        return self.view.mapToScene(self.view.viewport().rect()).boundingRect()

    def get_current_view_scale(self):
        scale = self.view.transform().m11()
        return scale
Example #3
0
class CarlaPatchbayW(QFrame, PluginEditParentMeta, HostWidgetMeta):
#class CarlaPatchbayW(QFrame, PluginEditParentMeta, HostWidgetMeta, metaclass=PyQtMetaClass):
    def __init__(self, parent, host, doSetup = True, onlyPatchbay = True, is3D = False):
        QFrame.__init__(self, parent)
        self.host = host

        if False:
            # kdevelop likes this :)
            host = CarlaHostMeta()
            self.host = host

        # -------------------------------------------------------------

        self.fLayout = QGridLayout(self)
        self.fLayout.setContentsMargins(0, 0, 0, 0)
        self.fLayout.setSpacing(1)
        self.setLayout(self.fLayout)

        self.fView = QGraphicsView(self)
        self.fKeys = PixmapKeyboardHArea(self)

        self.fPeaksIn  = DigitalPeakMeter(self)
        self.fPeaksOut = DigitalPeakMeter(self)
        self.fPeaksCleared = True

        self.fPeaksIn.setColor(DigitalPeakMeter.BLUE)
        self.fPeaksIn.setChannels(2)
        self.fPeaksIn.setOrientation(DigitalPeakMeter.VERTICAL)
        self.fPeaksIn.setFixedWidth(25)

        self.fPeaksOut.setColor(DigitalPeakMeter.GREEN)
        self.fPeaksOut.setChannels(2)
        self.fPeaksOut.setOrientation(DigitalPeakMeter.VERTICAL)
        self.fPeaksOut.setFixedWidth(25)

        self.fLayout.addWidget(self.fPeaksIn, 0, 0)
        self.fLayout.addWidget(self.fView, 0, 1) # self.fViewWidget if is3D else
        self.fLayout.addWidget(self.fPeaksOut, 0, 2)
        self.fLayout.addWidget(self.fKeys, 1, 0, 1, 0)

        # -------------------------------------------------------------
        # Internal stuff

        self.fParent      = parent
        self.fPluginCount = 0
        self.fPluginList  = []

        self.fExternalPatchbay = False
        self.fIsOnlyPatchbay   = onlyPatchbay
        self.fSelectedPlugins  = []

        self.fCanvasWidth  = 0
        self.fCanvasHeight = 0

        # -------------------------------------------------------------
        # Set-up Canvas Preview

        self.fMiniCanvasPreview = self.fParent.ui.miniCanvasPreview
        self.fMiniCanvasPreview.setRealParent(self)
        self.fMovingViaMiniCanvas = False

        # -------------------------------------------------------------
        # Set-up Canvas

        self.scene = patchcanvas.PatchScene(self, self.fView)
        self.fView.setScene(self.scene)
        self.fView.setRenderHint(QPainter.Antialiasing, bool(parent.fSavedSettings[CARLA_KEY_CANVAS_ANTIALIASING] == patchcanvas.ANTIALIASING_FULL))

        if parent.fSavedSettings[CARLA_KEY_CANVAS_USE_OPENGL] and hasGL: # and not is3D:
            self.fViewWidget = QGLWidget(self)
            self.fView.setViewport(self.fViewWidget)
            self.fView.setRenderHint(QPainter.HighQualityAntialiasing, parent.fSavedSettings[CARLA_KEY_CANVAS_HQ_ANTIALIASING])

        self.setupCanvas()

        QTimer.singleShot(100, self.slot_restoreScrollbarValues)

        # -------------------------------------------------------------
        # Connect actions to functions

        parent.ui.act_settings_show_meters.toggled.connect(self.slot_showCanvasMeters)
        parent.ui.act_settings_show_keyboard.toggled.connect(self.slot_showCanvasKeyboard)

        self.fView.horizontalScrollBar().valueChanged.connect(self.slot_horizontalScrollBarChanged)
        self.fView.verticalScrollBar().valueChanged.connect(self.slot_verticalScrollBarChanged)

        self.scene.scaleChanged.connect(self.slot_canvasScaleChanged)
        self.scene.sceneGroupMoved.connect(self.slot_canvasItemMoved)
        self.scene.pluginSelected.connect(self.slot_canvasPluginSelected)

        self.fMiniCanvasPreview.miniCanvasMoved.connect(self.slot_miniCanvasMoved)

        self.fKeys.keyboard.noteOn.connect(self.slot_noteOn)
        self.fKeys.keyboard.noteOff.connect(self.slot_noteOff)

        # -------------------------------------------------------------
        # Load Settings

        settings = QSettings()

        showMeters = settings.value("ShowMeters", False, type=bool)
        self.fParent.ui.act_settings_show_meters.setChecked(showMeters)
        self.fPeaksIn.setVisible(showMeters)
        self.fPeaksOut.setVisible(showMeters)

        showKeyboard = settings.value("ShowKeyboard", not(MACOS or WINDOWS), type=bool)
        self.fParent.ui.act_settings_show_keyboard.setChecked(showKeyboard)
        self.fKeys.setVisible(showKeyboard)

        # -------------------------------------------------------------
        # Connect actions to functions (part 2)

        host.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback)
        host.PluginRemovedCallback.connect(self.slot_handlePluginRemovedCallback)
        host.NoteOnCallback.connect(self.slot_handleNoteOnCallback)
        host.NoteOffCallback.connect(self.slot_handleNoteOffCallback)
        host.PatchbayClientAddedCallback.connect(self.slot_handlePatchbayClientAddedCallback)
        host.PatchbayClientRemovedCallback.connect(self.slot_handlePatchbayClientRemovedCallback)
        host.PatchbayClientRenamedCallback.connect(self.slot_handlePatchbayClientRenamedCallback)
        host.PatchbayClientDataChangedCallback.connect(self.slot_handlePatchbayClientDataChangedCallback)
        host.PatchbayPortAddedCallback.connect(self.slot_handlePatchbayPortAddedCallback)
        host.PatchbayPortRemovedCallback.connect(self.slot_handlePatchbayPortRemovedCallback)
        host.PatchbayPortRenamedCallback.connect(self.slot_handlePatchbayPortRenamedCallback)
        host.PatchbayConnectionAddedCallback.connect(self.slot_handlePatchbayConnectionAddedCallback)
        host.PatchbayConnectionRemovedCallback.connect(self.slot_handlePatchbayConnectionRemovedCallback)

        if not doSetup: return

        parent.ui.act_plugins_enable.triggered.connect(self.slot_pluginsEnable)
        parent.ui.act_plugins_disable.triggered.connect(self.slot_pluginsDisable)
        parent.ui.act_plugins_volume100.triggered.connect(self.slot_pluginsVolume100)
        parent.ui.act_plugins_mute.triggered.connect(self.slot_pluginsMute)
        parent.ui.act_plugins_wet100.triggered.connect(self.slot_pluginsWet100)
        parent.ui.act_plugins_bypass.triggered.connect(self.slot_pluginsBypass)
        parent.ui.act_plugins_center.triggered.connect(self.slot_pluginsCenter)
        parent.ui.act_plugins_panic.triggered.connect(self.slot_pluginsDisable)

        parent.ui.act_canvas_show_internal.triggered.connect(self.slot_canvasShowInternal)
        parent.ui.act_canvas_show_external.triggered.connect(self.slot_canvasShowExternal)
        parent.ui.act_canvas_arrange.setEnabled(False) # TODO, later
        parent.ui.act_canvas_arrange.triggered.connect(self.slot_canvasArrange)
        parent.ui.act_canvas_refresh.triggered.connect(self.slot_canvasRefresh)
        parent.ui.act_canvas_zoom_fit.triggered.connect(self.slot_canvasZoomFit)
        parent.ui.act_canvas_zoom_in.triggered.connect(self.slot_canvasZoomIn)
        parent.ui.act_canvas_zoom_out.triggered.connect(self.slot_canvasZoomOut)
        parent.ui.act_canvas_zoom_100.triggered.connect(self.slot_canvasZoomReset)
        parent.ui.act_canvas_print.triggered.connect(self.slot_canvasPrint)
        parent.ui.act_canvas_save_image.triggered.connect(self.slot_canvasSaveImage)

        parent.ui.act_settings_configure.triggered.connect(self.slot_configureCarla)

    # -----------------------------------------------------------------

    def getPluginEditDialog(self, pluginId):
        if pluginId >= self.fPluginCount:
            return None

        pedit = self.fPluginList[pluginId]
        if pedit is None:
            return None
        if False:
            pedit = DummyPluginEdit(self, 0)

        return pedit

    # -----------------------------------------------------------------

    @pyqtSlot(int, str)
    def slot_handlePluginAddedCallback(self, pluginId, pluginName):
        if self.fIsOnlyPatchbay:
            pedit = PluginEdit(self, self.host, pluginId)
        else:
            pedit = DummyPluginEdit(self, pluginId)

        self.fPluginList.append(pedit)
        self.fPluginCount += 1

        if self.fIsOnlyPatchbay and not self.fParent.isProjectLoading():
            self.host.set_active(pluginId, True)

    @pyqtSlot(int)
    def slot_handlePluginRemovedCallback(self, pluginId):
        patchcanvas.handlePluginRemoved(pluginId)

        if pluginId in self.fSelectedPlugins:
            self.clearSideStuff()

        pedit = self.getPluginEditDialog(pluginId)

        self.fPluginCount -= 1
        self.fPluginList.pop(pluginId)

        if pedit is not None:
            pedit.close()
            del pedit

        # push all plugins 1 slot back
        for i in range(pluginId, self.fPluginCount):
            pedit = self.fPluginList[i]
            pedit.setPluginId(i)

    @pyqtSlot(int, int, int, int)
    def slot_handleNoteOnCallback(self, pluginId, channel, note, velocity):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOn(note, False)

    @pyqtSlot(int, int, int)
    def slot_handleNoteOffCallback(self, pluginId, channel, note):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOff(note, False)

    # -----------------------------------------------------------------
    # HostWidgetMeta methods

    def removeAllPlugins(self):
        patchcanvas.handleAllPluginsRemoved()

        for pedit in self.fPluginList:
            if pedit is None:
                break
            pedit.close()
            del pedit

        self.fPluginCount = 0
        self.fPluginList  = []

        self.clearSideStuff()

    def engineStarted(self):
        pass

    def engineStopped(self):
        patchcanvas.clear()

    def idleFast(self):
        if self.fPluginCount == 0:
            return

        for pluginId in self.fSelectedPlugins:
            self.fPeaksCleared = False
            if self.fPeaksIn.isVisible():
                self.fPeaksIn.displayMeter(1, self.host.get_input_peak_value(pluginId, True))
                self.fPeaksIn.displayMeter(2, self.host.get_input_peak_value(pluginId, False))
            if self.fPeaksOut.isVisible():
                self.fPeaksOut.displayMeter(1, self.host.get_output_peak_value(pluginId, True))
                self.fPeaksOut.displayMeter(2, self.host.get_output_peak_value(pluginId, False))
            return

        if self.fPeaksCleared:
            return

        self.fPeaksCleared = True
        self.fPeaksIn.displayMeter(1, 0.0, True)
        self.fPeaksIn.displayMeter(2, 0.0, True)
        self.fPeaksOut.displayMeter(1, 0.0, True)
        self.fPeaksOut.displayMeter(2, 0.0, True)

    def idleSlow(self):
        for pedit in self.fPluginList:
            if pedit is None:
                break
            pedit.idleSlow()

    def projectLoadingStarted(self):
        self.fView.setEnabled(False)

    def projectLoadingFinished(self):
        self.fView.setEnabled(True)
        QTimer.singleShot(1000, self.slot_canvasRefresh)

    def saveSettings(self, settings):
        settings.setValue("ShowMeters", self.fParent.ui.act_settings_show_meters.isChecked())
        settings.setValue("ShowKeyboard", self.fParent.ui.act_settings_show_keyboard.isChecked())
        settings.setValue("HorizontalScrollBarValue", self.fView.horizontalScrollBar().value())
        settings.setValue("VerticalScrollBarValue", self.fView.verticalScrollBar().value())

    def showEditDialog(self, pluginId):
        pedit = self.getPluginEditDialog(pluginId)

        if pedit:
            pedit.show()

    # -----------------------------------------------------------------
    # PluginEdit callbacks

    def editDialogVisibilityChanged(self, pluginId, visible):
        pass

    def editDialogPluginHintsChanged(self, pluginId, hints):
        pass

    def editDialogParameterValueChanged(self, pluginId, parameterId, value):
        pass

    def editDialogProgramChanged(self, pluginId, index):
        pass

    def editDialogMidiProgramChanged(self, pluginId, index):
        pass

    def editDialogNotePressed(self, pluginId, note):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOn(note, False)

    def editDialogNoteReleased(self, pluginId, note):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOff(note, False)

    def editDialogMidiActivityChanged(self, pluginId, onOff):
        pass

    # -----------------------------------------------------------------

    def clearSideStuff(self):
        self.scene.clearSelection()

        self.fSelectedPlugins = []

        self.fKeys.keyboard.allNotesOff(False)
        self.fKeys.setEnabled(False)

        self.fPeaksCleared = True
        self.fPeaksIn.displayMeter(1, 0.0, True)
        self.fPeaksIn.displayMeter(2, 0.0, True)
        self.fPeaksOut.displayMeter(1, 0.0, True)
        self.fPeaksOut.displayMeter(2, 0.0, True)

    def setupCanvas(self):
        pOptions = patchcanvas.options_t()
        pOptions.theme_name       = self.fParent.fSavedSettings[CARLA_KEY_CANVAS_THEME]
        pOptions.auto_hide_groups = self.fParent.fSavedSettings[CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS]
        pOptions.use_bezier_lines = self.fParent.fSavedSettings[CARLA_KEY_CANVAS_USE_BEZIER_LINES]
        pOptions.antialiasing     = self.fParent.fSavedSettings[CARLA_KEY_CANVAS_ANTIALIASING]
        pOptions.eyecandy         = self.fParent.fSavedSettings[CARLA_KEY_CANVAS_EYE_CANDY]

        pFeatures = patchcanvas.features_t()
        pFeatures.group_info   = False
        pFeatures.group_rename = False
        pFeatures.port_info    = False
        pFeatures.port_rename  = False
        pFeatures.handle_group_pos = True

        patchcanvas.setOptions(pOptions)
        patchcanvas.setFeatures(pFeatures)
        patchcanvas.init("Carla2", self.scene, canvasCallback, False)

        tryCanvasSize = self.fParent.fSavedSettings[CARLA_KEY_CANVAS_SIZE].split("x")

        if len(tryCanvasSize) == 2 and tryCanvasSize[0].isdigit() and tryCanvasSize[1].isdigit():
            self.fCanvasWidth  = int(tryCanvasSize[0])
            self.fCanvasHeight = int(tryCanvasSize[1])
        else:
            self.fCanvasWidth  = CARLA_DEFAULT_CANVAS_SIZE_WIDTH
            self.fCanvasHeight = CARLA_DEFAULT_CANVAS_SIZE_HEIGHT

        patchcanvas.setCanvasSize(0, 0, self.fCanvasWidth, self.fCanvasHeight)
        patchcanvas.setInitialPos(self.fCanvasWidth / 2, self.fCanvasHeight / 2)
        self.fView.setSceneRect(0, 0, self.fCanvasWidth, self.fCanvasHeight)

        self.themeData = [self.fCanvasWidth, self.fCanvasHeight, patchcanvas.canvas.theme.canvas_bg, patchcanvas.canvas.theme.rubberband_brush, patchcanvas.canvas.theme.rubberband_pen.color()]

    def updateCanvasInitialPos(self):
        x = self.fView.horizontalScrollBar().value() + self.width()/4
        y = self.fView.verticalScrollBar().value() + self.height()/4
        patchcanvas.setInitialPos(x, y)

    # -----------------------------------------------------------------

    @pyqtSlot(bool)
    def slot_showCanvasMeters(self, yesNo):
        self.fPeaksIn.setVisible(yesNo)
        self.fPeaksOut.setVisible(yesNo)

    @pyqtSlot(bool)
    def slot_showCanvasKeyboard(self, yesNo):
        self.fKeys.setVisible(yesNo)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_miniCanvasCheckAll(self):
        self.slot_miniCanvasCheckSize()
        self.slot_horizontalScrollBarChanged(self.fView.horizontalScrollBar().value())
        self.slot_verticalScrollBarChanged(self.fView.verticalScrollBar().value())

    @pyqtSlot()
    def slot_miniCanvasCheckSize(self):
        self.fMiniCanvasPreview.setViewSize(float(self.width()) / self.fCanvasWidth, float(self.height()) / self.fCanvasHeight)

    @pyqtSlot(int)
    def slot_horizontalScrollBarChanged(self, value):
        if self.fMovingViaMiniCanvas: return

        maximum = self.fView.horizontalScrollBar().maximum()
        if maximum == 0:
            xp = 0
        else:
            xp = float(value) / maximum
        self.fMiniCanvasPreview.setViewPosX(xp)
        self.updateCanvasInitialPos()

    @pyqtSlot(int)
    def slot_verticalScrollBarChanged(self, value):
        if self.fMovingViaMiniCanvas: return

        maximum = self.fView.verticalScrollBar().maximum()
        if maximum == 0:
            yp = 0
        else:
            yp = float(value) / maximum
        self.fMiniCanvasPreview.setViewPosY(yp)
        self.updateCanvasInitialPos()

    @pyqtSlot()
    def slot_restoreScrollbarValues(self):
        settings = QSettings()
        self.fView.horizontalScrollBar().setValue(settings.value("HorizontalScrollBarValue", self.fView.horizontalScrollBar().maximum()/2, type=int))
        self.fView.verticalScrollBar().setValue(settings.value("VerticalScrollBarValue", self.fView.verticalScrollBar().maximum()/2, type=int))

    # -----------------------------------------------------------------

    @pyqtSlot(float)
    def slot_canvasScaleChanged(self, scale):
        self.fMiniCanvasPreview.setViewScale(scale)

    @pyqtSlot(int, int, QPointF)
    def slot_canvasItemMoved(self, group_id, split_mode, pos):
        self.fMiniCanvasPreview.update()

    @pyqtSlot(list)
    def slot_canvasPluginSelected(self, pluginList):
        self.fKeys.keyboard.allNotesOff(False)
        self.fKeys.setEnabled(len(pluginList) != 0) # and self.fPluginCount > 0
        self.fSelectedPlugins = pluginList

    @pyqtSlot(float, float)
    def slot_miniCanvasMoved(self, xp, yp):
        self.fMovingViaMiniCanvas = True
        self.fView.horizontalScrollBar().setValue(xp * self.fView.horizontalScrollBar().maximum())
        self.fView.verticalScrollBar().setValue(yp * self.fView.verticalScrollBar().maximum())
        self.fMovingViaMiniCanvas = False
        self.updateCanvasInitialPos()

    # -----------------------------------------------------------------

    @pyqtSlot(int)
    def slot_noteOn(self, note):
        for pluginId in self.fSelectedPlugins:
            self.host.send_midi_note(pluginId, 0, note, 100)

            pedit = self.getPluginEditDialog(pluginId)
            pedit.noteOn(0, note, 100)

    @pyqtSlot(int)
    def slot_noteOff(self, note):
        for pluginId in self.fSelectedPlugins:
            self.host.send_midi_note(pluginId, 0, note, 0)

            pedit = self.getPluginEditDialog(pluginId)
            pedit.noteOff(0, note)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_pluginsEnable(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            self.host.set_active(i, True)

    @pyqtSlot()
    def slot_pluginsDisable(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            self.host.set_active(i, False)

    @pyqtSlot()
    def slot_pluginsVolume100(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_VOLUME:
                pedit.setParameterValue(PARAMETER_VOLUME, 1.0)
                self.host.set_volume(i, 1.0)

    @pyqtSlot()
    def slot_pluginsMute(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_VOLUME:
                pedit.setParameterValue(PARAMETER_VOLUME, 0.0)
                self.host.set_volume(i, 0.0)

    @pyqtSlot()
    def slot_pluginsWet100(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_DRYWET:
                pedit.setParameterValue(PARAMETER_DRYWET, 1.0)
                self.host.set_drywet(i, 1.0)

    @pyqtSlot()
    def slot_pluginsBypass(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_DRYWET:
                pedit.setParameterValue(PARAMETER_DRYWET, 0.0)
                self.host.set_drywet(i, 0.0)

    @pyqtSlot()
    def slot_pluginsCenter(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_BALANCE:
                pedit.setParameterValue(PARAMETER_BALANCE_LEFT, -1.0)
                pedit.setParameterValue(PARAMETER_BALANCE_RIGHT, 1.0)
                self.host.set_balance_left(i, -1.0)
                self.host.set_balance_right(i, 1.0)

            if pedit.getHints() & PLUGIN_CAN_PANNING:
                pedit.setParameterValue(PARAMETER_PANNING, 0.0)
                self.host.set_panning(i, 0.0)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_configureCarla(self):
        dialog = CarlaSettingsW(self, self.host, True, hasGL)
        if not dialog.exec_():
            return

        self.fParent.loadSettings(False)

        patchcanvas.clear()

        self.setupCanvas()
        self.fParent.updateContainer(self.themeData)
        self.slot_miniCanvasCheckAll()

        if self.host.is_engine_running():
            self.host.patchbay_refresh(self.fExternalPatchbay)

    # -----------------------------------------------------------------

    @pyqtSlot(int, int, int, str)
    def slot_handlePatchbayClientAddedCallback(self, clientId, clientIcon, pluginId, clientName):
        pcSplit = patchcanvas.SPLIT_UNDEF
        pcIcon  = patchcanvas.ICON_APPLICATION

        if clientIcon == PATCHBAY_ICON_PLUGIN:
            pcIcon = patchcanvas.ICON_PLUGIN
        if clientIcon == PATCHBAY_ICON_HARDWARE:
            pcIcon = patchcanvas.ICON_HARDWARE
        elif clientIcon == PATCHBAY_ICON_CARLA:
            pass
        elif clientIcon == PATCHBAY_ICON_DISTRHO:
            pcIcon = patchcanvas.ICON_DISTRHO
        elif clientIcon == PATCHBAY_ICON_FILE:
            pcIcon = patchcanvas.ICON_FILE

        patchcanvas.addGroup(clientId, clientName, pcSplit, pcIcon)

        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

        if pluginId < 0:
            return
        if pluginId >= self.fPluginCount:
            print("sorry, can't map this plugin to canvas client", pluginId, self.fPluginCount)
            return

        patchcanvas.setGroupAsPlugin(clientId, pluginId, bool(self.host.get_plugin_info(pluginId)['hints'] & PLUGIN_HAS_CUSTOM_UI))

    @pyqtSlot(int)
    def slot_handlePatchbayClientRemovedCallback(self, clientId):
        #if not self.fEngineStarted: return
        patchcanvas.removeGroup(clientId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, str)
    def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName):
        patchcanvas.renameGroup(clientId, newClientName)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, int)
    def slot_handlePatchbayClientDataChangedCallback(self, clientId, clientIcon, pluginId):
        pcIcon = patchcanvas.ICON_APPLICATION

        if clientIcon == PATCHBAY_ICON_PLUGIN:
            pcIcon = patchcanvas.ICON_PLUGIN
        if clientIcon == PATCHBAY_ICON_HARDWARE:
            pcIcon = patchcanvas.ICON_HARDWARE
        elif clientIcon == PATCHBAY_ICON_CARLA:
            pass
        elif clientIcon == PATCHBAY_ICON_DISTRHO:
            pcIcon = patchcanvas.ICON_DISTRHO
        elif clientIcon == PATCHBAY_ICON_FILE:
            pcIcon = patchcanvas.ICON_FILE

        patchcanvas.setGroupIcon(clientId, pcIcon)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

        if pluginId < 0:
            return
        if pluginId >= self.fPluginCount:
            print("sorry, can't map this plugin to canvas client", pluginId, self.fPluginCount)
            return

        patchcanvas.setGroupAsPlugin(clientId, pluginId, bool(self.host.get_plugin_info(pluginId)['hints'] & PLUGIN_HAS_CUSTOM_UI))

    @pyqtSlot(int, int, int, str)
    def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portFlags, portName):
        isAlternate = False

        if (portFlags & PATCHBAY_PORT_IS_INPUT):
            portMode = patchcanvas.PORT_MODE_INPUT
        else:
            portMode = patchcanvas.PORT_MODE_OUTPUT

        if (portFlags & PATCHBAY_PORT_TYPE_AUDIO):
            portType = patchcanvas.PORT_TYPE_AUDIO_JACK
        elif (portFlags & PATCHBAY_PORT_TYPE_CV):
            isAlternate = True
            portType = patchcanvas.PORT_TYPE_AUDIO_JACK
        elif (portFlags & PATCHBAY_PORT_TYPE_MIDI):
            portType = patchcanvas.PORT_TYPE_MIDI_JACK
        else:
            portType = patchcanvas.PORT_TYPE_NULL

        patchcanvas.addPort(clientId, portId, portName, portMode, portType, isAlternate)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int)
    def slot_handlePatchbayPortRemovedCallback(self, groupId, portId):
        #if not self.fEngineStarted: return
        patchcanvas.removePort(groupId, portId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, str)
    def slot_handlePatchbayPortRenamedCallback(self, groupId, portId, newPortName):
        patchcanvas.renamePort(groupId, portId, newPortName)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, int, int, int)
    def slot_handlePatchbayConnectionAddedCallback(self, connectionId, groupOutId, portOutId, groupInId, portInId):
        patchcanvas.connectPorts(connectionId, groupOutId, portOutId, groupInId, portInId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, int)
    def slot_handlePatchbayConnectionRemovedCallback(self, connectionId, portOutId, portInId):
        #if not self.fEngineStarted: return
        patchcanvas.disconnectPorts(connectionId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_canvasArrange(self):
        patchcanvas.arrange()

    @pyqtSlot()
    def slot_canvasShowInternal(self):
        self.fExternalPatchbay = False
        self.fParent.ui.act_canvas_show_internal.blockSignals(True)
        self.fParent.ui.act_canvas_show_external.blockSignals(True)
        self.fParent.ui.act_canvas_show_internal.setChecked(True)
        self.fParent.ui.act_canvas_show_external.setChecked(False)
        self.fParent.ui.act_canvas_show_internal.blockSignals(False)
        self.fParent.ui.act_canvas_show_external.blockSignals(False)
        self.slot_canvasRefresh()

    @pyqtSlot()
    def slot_canvasShowExternal(self):
        self.fExternalPatchbay = True
        self.fParent.ui.act_canvas_show_internal.blockSignals(True)
        self.fParent.ui.act_canvas_show_external.blockSignals(True)
        self.fParent.ui.act_canvas_show_internal.setChecked(False)
        self.fParent.ui.act_canvas_show_external.setChecked(True)
        self.fParent.ui.act_canvas_show_internal.blockSignals(False)
        self.fParent.ui.act_canvas_show_external.blockSignals(False)
        self.slot_canvasRefresh()

    @pyqtSlot()
    def slot_canvasRefresh(self):
        patchcanvas.clear()

        if self.host.is_engine_running():
            self.host.patchbay_refresh(self.fExternalPatchbay)

            for pedit in self.fPluginList:
                if pedit is None:
                    break
                pedit.reloadAll()

        QTimer.singleShot(1000 if self.fParent.fSavedSettings[CARLA_KEY_CANVAS_EYE_CANDY] else 0, self.fMiniCanvasPreview.update)

    @pyqtSlot()
    def slot_canvasZoomFit(self):
        self.scene.zoom_fit()

    @pyqtSlot()
    def slot_canvasZoomIn(self):
        self.scene.zoom_in()

    @pyqtSlot()
    def slot_canvasZoomOut(self):
        self.scene.zoom_out()

    @pyqtSlot()
    def slot_canvasZoomReset(self):
        self.scene.zoom_reset()

    @pyqtSlot()
    def slot_canvasPrint(self):
        self.scene.clearSelection()
        self.fExportPrinter = QPrinter()
        dialog = QPrintDialog(self.fExportPrinter, self)

        if dialog.exec_():
            painter = QPainter(self.fExportPrinter)
            painter.save()
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setRenderHint(QPainter.TextAntialiasing)
            self.scene.render(painter)
            painter.restore()

    @pyqtSlot()
    def slot_canvasSaveImage(self):
        newPath = QFileDialog.getSaveFileName(self, self.tr("Save Image"), filter=self.tr("PNG Image (*.png);;JPEG Image (*.jpg)"))

        if config_UseQt5:
            newPath = newPath[0]
        if not newPath:
            return

        self.scene.clearSelection()

        if newPath.lower().endswith((".jpg",)):
            imgFormat = "JPG"
        elif newPath.lower().endswith((".png",)):
            imgFormat = "PNG"
        else:
            # File-dialog may not auto-add the extension
            imgFormat = "PNG"
            newPath  += ".png"

        self.fExportImage = QImage(self.scene.sceneRect().width(), self.scene.sceneRect().height(), QImage.Format_RGB32)
        painter = QPainter(self.fExportImage)
        painter.save()
        painter.setRenderHint(QPainter.Antialiasing) # TODO - set true, cleanup this
        painter.setRenderHint(QPainter.TextAntialiasing)
        self.scene.render(painter)
        self.fExportImage.save(newPath, imgFormat, 100)
        painter.restore()

    # -----------------------------------------------------------------

    def resizeEvent(self, event):
        QFrame.resizeEvent(self, event)
        self.slot_miniCanvasCheckSize()
Example #4
0
class View(QWidget):

    trigger_focus_event = QtCore.pyqtSignal(str)

    def __init__(self, emacs_xid, buffer, view_info):
        super(View, self).__init__()

        self.buffer = buffer

        self.emacs_xid = emacs_xid

        # Init widget attributes.
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True)
        self.setContentsMargins(0, 0, 0, 0)
        self.installEventFilter(self)

        # Init attributes.
        self.view_info = view_info
        (self.buffer_id, self.x, self.y, self.width,
         self.height) = view_info.split(":")
        self.x = int(self.x)
        self.y = int(self.y)
        self.width = int(self.width)
        self.height = int(self.height)

        # Build QGraphicsView.
        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.graphics_view = QGraphicsView(buffer, self)
        self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setRenderHints(QPainter.Antialiasing
                                          | QPainter.SmoothPixmapTransform
                                          | QPainter.TextAntialiasing)
        # Remove damn border from QGraphicsView.
        self.graphics_view.setFrameStyle(0)
        self.graphics_view.setStyleSheet(
            "QGraphicsView {background: transparent; border: 3px; outline: none;}"
        )
        self.layout.addWidget(self.graphics_view)

        # NOTE: show function must start before resize to trigger *first* resizeEvent after show.
        self.show()

        # Resize after show to trigger fit view operation.
        self.resize(self.width, self.height)

    def resizeEvent(self, event):
        # Fit content to view rect just when buffer fit_to_view option is enable.
        if self.buffer.fit_to_view:
            if event.oldSize().isValid():
                self.graphics_view.fitInView(
                    self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio)
        QWidget.resizeEvent(self, event)

    def eventFilter(self, obj, event):
        # Focus emacs buffer when user click view.
        if event.type() in [
                QEvent.MouseButtonPress, QEvent.MouseButtonRelease,
                QEvent.MouseMove, QEvent.MouseButtonDblClick, QEvent.Wheel
        ]:
            self.trigger_focus_event.emit("{0},{1}".format(
                event.globalX(), event.globalY()))

        return False

    def showEvent(self, event):
        # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed.
        self.reparent()

        # Make graphics view at left-top corner after show.
        self.graphics_view.verticalScrollBar().setValue(0)
        self.graphics_view.horizontalScrollBar().setValue(0)

    def reparent(self):
        xlib_display = get_xlib_display()

        view_xid = self.winId().__int__()
        view_xwindow = xlib_display.create_resource_object("window", view_xid)
        emacs_xwindow = xlib_display.create_resource_object(
            "window", self.emacs_xid)

        view_xwindow.reparent(emacs_xwindow, self.x, self.y)

        xlib_display.sync()

    def handle_destroy(self):
        self.destroy()
Example #5
0
class View(QWidget):

    trigger_focus_event = QtCore.pyqtSignal(str)

    def __init__(self, buffer, view_info):
        super(View, self).__init__()

        self.buffer = buffer

        # Init widget attributes.
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True)
        self.setContentsMargins(0, 0, 0, 0)
        self.installEventFilter(self)

        # Init attributes.
        self.view_info = view_info
        (self.buffer_id, self.emacs_xid, self.x, self.y, self.width,
         self.height) = view_info.split(":")
        self.emacs_xid = int(self.emacs_xid)
        self.x = int(self.x)
        self.y = int(self.y)
        self.width = int(self.width)
        self.height = int(self.height)

        # Build QGraphicsView.
        self.layout = QVBoxLayout(self)
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.graphics_view = QGraphicsView(buffer, self)

        # Set background color.
        # When fit_to_view is True, QGraphicsView will fill color around app view.
        # We fill color with buffer's attribute "background_color".
        if hasattr(self.buffer,
                   "background_color") and self.buffer.background_color:
            self.graphics_view.setBackgroundBrush(
                QBrush(self.buffer.background_color))

        # Remove border from QGraphicsView.
        self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setRenderHints(QPainter.Antialiasing
                                          | QPainter.SmoothPixmapTransform
                                          | QPainter.TextAntialiasing)
        self.graphics_view.setFrameStyle(QFrame.NoFrame)

        # Add graphics view.
        self.layout.addWidget(self.graphics_view)

        # NOTE: show function must start before resize to trigger *first* resizeEvent after show.
        self.show()

        # Resize after show to trigger fit view operation.
        self.resize(self.width, self.height)

        self.buffer.aspect_ratio_change.connect(self.adjust_aspect_ratio)

    def resizeEvent(self, event):
        # Fit content to view rect just when buffer fit_to_view option is enable.
        if self.buffer.fit_to_view:
            if event.oldSize().isValid():
                self.graphics_view.fitInView(
                    self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio)
        QWidget.resizeEvent(self, event)

    def adjust_aspect_ratio(self):
        widget_width = self.width
        widget_height = self.height

        if self.buffer.aspect_ratio == 0:
            self.buffer.buffer_widget.resize(self.width, self.height)

            self.layout.setContentsMargins(0, 0, 0, 0)
        else:
            view_height = widget_height * (
                1 - 2 * self.buffer.vertical_padding_ratio)
            view_width = view_height * self.buffer.aspect_ratio
            horizontal_padding = (widget_width - view_width) / 2
            vertical_padding = self.buffer.vertical_padding_ratio * widget_height

            self.buffer.buffer_widget.resize(view_width, view_height)

            self.layout.setContentsMargins(horizontal_padding,
                                           vertical_padding,
                                           horizontal_padding,
                                           vertical_padding)

    def eventFilter(self, obj, event):
        # When we press Alt + Tab in operating system.
        # Emacs window cannot get the focus normally if mouse in EAF buffer area.
        #
        # So we use wmctrl activate on Emacs window after Alt + Tab operation.
        #
        # NOTE: turn off this behavior under i3 window manager.
        if event.type() in [QEvent.ShortcutOverride]:
            import os
            if os.environ.get("DESKTOP_SESSION") != "i3":
                if not activate_emacs_window():
                    self.buffer.message_to_emacs.emit(
                        "You need install tool 'wmctrl' to activate Emacs window, make Emacs input correctly after Alt + Tab operation."
                    )

        # Focus emacs buffer when user click view.
        if event.type() in [
                QEvent.MouseButtonPress, QEvent.MouseButtonRelease,
                QEvent.MouseButtonDblClick, QEvent.Wheel
        ]:
            self.trigger_focus_event.emit(self.buffer_id)
            # Stop mouse event.
            return True

        return False

    def showEvent(self, event):
        # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed.
        self.reparent()

        # Make graphics view at left-top corner after show.
        self.graphics_view.verticalScrollBar().setValue(0)
        self.graphics_view.horizontalScrollBar().setValue(0)

    def reparent(self):
        qwindow = self.windowHandle()
        qwindow.setParent(QWindow.fromWinId(self.emacs_xid))
        qwindow.setPosition(QPoint(self.x, self.y))

    def destroy_view(self):
        self.destroy()
Example #6
0
class View(QWidget):

    trigger_focus_event = QtCore.pyqtSignal(str)

    def __init__(self, emacs_xid, buffer, view_info):
        super(View, self).__init__()

        self.buffer = buffer

        self.emacs_xid = emacs_xid

        # Init widget attributes.
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True)
        self.setContentsMargins(0, 0, 0, 0)
        self.installEventFilter(self)

        # Init attributes.
        self.view_info = view_info
        (self.buffer_id, self.x, self.y, self.width, self.height) = view_info.split(":")
        self.x = int(self.x)
        self.y = int(self.y)
        self.width = int(self.width)
        self.height = int(self.height)

        # Build QGraphicsView.
        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.graphics_view = QGraphicsView(buffer, self)
        self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing)
        # Remove damn border from QGraphicsView.
        self.graphics_view.setFrameStyle(0)
        self.graphics_view.setStyleSheet("QGraphicsView {background: transparent; border: 3px; outline: none;}")
        self.layout.addWidget(self.graphics_view)

        # NOTE: show function must start before resize to trigger *first* resizeEvent after show.
        self.show()

        # Resize after show to trigger fit view operation.
        self.resize(self.width, self.height)

    def resizeEvent(self, event):
        # Fit content to view rect just when buffer fit_to_view option is enable.
        if self.buffer.fit_to_view:
            if event.oldSize().isValid():
                self.graphics_view.fitInView(self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio)
        QWidget.resizeEvent(self, event)

    def eventFilter(self, obj, event):
        # Focus emacs buffer when user click view.
        if event.type() in [QEvent.MouseButtonPress, QEvent.MouseButtonRelease,
                            QEvent.MouseMove, QEvent.MouseButtonDblClick, QEvent.Wheel]:
            # Send mouse event to applicatin view.
            self.trigger_focus_event.emit("{0},{1}".format(event.globalX(), event.globalY()))

            # Stop mouse event.
            return True

        return False

    def showEvent(self, event):
        # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed.
        self.reparent()

        # Make graphics view at left-top corner after show.
        self.graphics_view.verticalScrollBar().setValue(0)
        self.graphics_view.horizontalScrollBar().setValue(0)

    def reparent(self):
        xlib_display = get_xlib_display()

        view_xid = self.winId().__int__()
        view_xwindow = xlib_display.create_resource_object("window", view_xid)
        emacs_xwindow = xlib_display.create_resource_object("window", self.emacs_xid)

        view_xwindow.reparent(emacs_xwindow, self.x, self.y)

        xlib_display.sync()

    def handle_destroy(self):
        self.destroy()
class View(QWidget):

    trigger_focus_event = QtCore.pyqtSignal(str)

    def __init__(self, buffer, view_info):
        super(View, self).__init__()

        self.buffer = buffer

        # Init widget attributes.
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_X11DoNotAcceptFocus, True)
        self.setContentsMargins(0, 0, 0, 0)
        self.installEventFilter(self)

        # Init attributes.
        self.view_info = view_info
        (self.buffer_id, self.emacs_xid, self.x, self.y, self.width,
         self.height) = view_info.split(":")
        self.emacs_xid = int(self.emacs_xid)
        self.x = int(self.x)
        self.y = int(self.y)
        self.width = int(self.width)
        self.height = int(self.height)

        # Build QGraphicsView.
        self.layout = QVBoxLayout(self)
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.graphics_view = QGraphicsView(buffer, self)
        self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphics_view.setRenderHints(QPainter.Antialiasing
                                          | QPainter.SmoothPixmapTransform
                                          | QPainter.TextAntialiasing)
        # Remove damn border from QGraphicsView.
        self.graphics_view.setFrameStyle(QFrame.NoFrame)
        self.layout.addWidget(self.graphics_view)

        # NOTE: show function must start before resize to trigger *first* resizeEvent after show.
        self.show()

        # Resize after show to trigger fit view operation.
        self.resize(self.width, self.height)

        self.buffer.aspect_ratio_change.connect(self.adjust_aspect_ratio)

    def resizeEvent(self, event):
        # Fit content to view rect just when buffer fit_to_view option is enable.
        if self.buffer.fit_to_view:
            if event.oldSize().isValid():
                self.graphics_view.fitInView(
                    self.graphics_view.scene().sceneRect(), Qt.KeepAspectRatio)
        QWidget.resizeEvent(self, event)

    def adjust_aspect_ratio(self):
        widget_width = self.width
        widget_height = self.height

        if self.buffer.aspect_ratio == 0:
            self.buffer.buffer_widget.resize(self.width, self.height)

            self.layout.setContentsMargins(0, 0, 0, 0)
        else:
            view_height = widget_height * (
                1 - 2 * self.buffer.vertical_padding_ratio)
            view_width = view_height * self.buffer.aspect_ratio
            horizontal_padding = (widget_width - view_width) / 2
            vertical_padding = self.buffer.vertical_padding_ratio * widget_height

            self.buffer.buffer_widget.resize(view_width, view_height)

            self.layout.setContentsMargins(horizontal_padding,
                                           vertical_padding,
                                           horizontal_padding,
                                           vertical_padding)

    def eventFilter(self, obj, event):
        # Focus emacs buffer when user click view.
        if event.type() in [
                QEvent.MouseButtonPress, QEvent.MouseButtonRelease,
                QEvent.MouseButtonDblClick, QEvent.Wheel
        ]:
            self.trigger_focus_event.emit(self.buffer_id)
            # Stop mouse event.
            return True

        return False

    def showEvent(self, event):
        # NOTE: we must reparent after widget show, otherwise reparent operation maybe failed.
        self.reparent()

        # Make graphics view at left-top corner after show.
        self.graphics_view.verticalScrollBar().setValue(0)
        self.graphics_view.horizontalScrollBar().setValue(0)

    def reparent(self):
        qwindow = self.windowHandle()
        qwindow.setParent(QWindow.fromWinId(self.emacs_xid))
        qwindow.setPosition(QPoint(self.x, self.y))

    def destroy_view(self):
        self.destroy()
Example #8
0
class CarlaPatchbayW(QFrame, PluginEditParentMeta, HostWidgetMeta):
    #class CarlaPatchbayW(QFrame, PluginEditParentMeta, HostWidgetMeta, metaclass=PyQtMetaClass):
    def __init__(self,
                 parent,
                 host,
                 doSetup=True,
                 onlyPatchbay=True,
                 is3D=False):
        QFrame.__init__(self, parent)
        self.host = host

        if False:
            # kdevelop likes this :)
            host = CarlaHostMeta()
            self.host = host

        # -------------------------------------------------------------

        self.fLayout = QGridLayout(self)
        self.fLayout.setContentsMargins(0, 0, 0, 0)
        self.fLayout.setSpacing(1)
        self.setLayout(self.fLayout)

        self.fView = QGraphicsView(self)
        self.fKeys = PixmapKeyboardHArea(self)

        self.fPeaksIn = DigitalPeakMeter(self)
        self.fPeaksOut = DigitalPeakMeter(self)
        self.fPeaksCleared = True

        self.fPeaksIn.setColor(DigitalPeakMeter.BLUE)
        self.fPeaksIn.setChannels(2)
        self.fPeaksIn.setOrientation(DigitalPeakMeter.VERTICAL)
        self.fPeaksIn.setFixedWidth(25)

        self.fPeaksOut.setColor(DigitalPeakMeter.GREEN)
        self.fPeaksOut.setChannels(2)
        self.fPeaksOut.setOrientation(DigitalPeakMeter.VERTICAL)
        self.fPeaksOut.setFixedWidth(25)

        self.fLayout.addWidget(self.fPeaksIn, 0, 0)
        self.fLayout.addWidget(self.fView, 0,
                               1)  # self.fViewWidget if is3D else
        self.fLayout.addWidget(self.fPeaksOut, 0, 2)
        self.fLayout.addWidget(self.fKeys, 1, 0, 1, 0)

        # -------------------------------------------------------------
        # Internal stuff

        self.fParent = parent
        self.fPluginCount = 0
        self.fPluginList = []

        self.fExternalPatchbay = False
        self.fIsOnlyPatchbay = onlyPatchbay
        self.fSelectedPlugins = []

        self.fCanvasWidth = 0
        self.fCanvasHeight = 0

        # -------------------------------------------------------------
        # Set-up Canvas Preview

        self.fMiniCanvasPreview = self.fParent.ui.miniCanvasPreview
        self.fMiniCanvasPreview.setRealParent(self)
        self.fMovingViaMiniCanvas = False

        # -------------------------------------------------------------
        # Set-up Canvas

        self.scene = patchcanvas.PatchScene(self, self.fView)
        self.fView.setScene(self.scene)
        self.fView.setRenderHint(
            QPainter.Antialiasing,
            bool(parent.fSavedSettings[CARLA_KEY_CANVAS_ANTIALIASING] ==
                 patchcanvas.ANTIALIASING_FULL))

        if parent.fSavedSettings[
                CARLA_KEY_CANVAS_USE_OPENGL] and hasGL:  # and not is3D:
            self.fViewWidget = QGLWidget(self)
            self.fView.setViewport(self.fViewWidget)
            self.fView.setRenderHint(
                QPainter.HighQualityAntialiasing,
                parent.fSavedSettings[CARLA_KEY_CANVAS_HQ_ANTIALIASING])

        self.setupCanvas()

        QTimer.singleShot(100, self.slot_restoreScrollbarValues)

        # -------------------------------------------------------------
        # Connect actions to functions

        parent.ui.act_settings_show_meters.toggled.connect(
            self.slot_showCanvasMeters)
        parent.ui.act_settings_show_keyboard.toggled.connect(
            self.slot_showCanvasKeyboard)

        self.fView.horizontalScrollBar().valueChanged.connect(
            self.slot_horizontalScrollBarChanged)
        self.fView.verticalScrollBar().valueChanged.connect(
            self.slot_verticalScrollBarChanged)

        self.scene.scaleChanged.connect(self.slot_canvasScaleChanged)
        self.scene.sceneGroupMoved.connect(self.slot_canvasItemMoved)
        self.scene.pluginSelected.connect(self.slot_canvasPluginSelected)

        self.fMiniCanvasPreview.miniCanvasMoved.connect(
            self.slot_miniCanvasMoved)

        self.fKeys.keyboard.noteOn.connect(self.slot_noteOn)
        self.fKeys.keyboard.noteOff.connect(self.slot_noteOff)

        # -------------------------------------------------------------
        # Load Settings

        settings = QSettings()

        showMeters = settings.value("ShowMeters", False, type=bool)
        self.fParent.ui.act_settings_show_meters.setChecked(showMeters)
        self.fPeaksIn.setVisible(showMeters)
        self.fPeaksOut.setVisible(showMeters)

        showKeyboard = settings.value("ShowKeyboard",
                                      not (MACOS or WINDOWS),
                                      type=bool)
        self.fParent.ui.act_settings_show_keyboard.setChecked(showKeyboard)
        self.fKeys.setVisible(showKeyboard)

        # -------------------------------------------------------------
        # Connect actions to functions (part 2)

        host.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback)
        host.PluginRemovedCallback.connect(
            self.slot_handlePluginRemovedCallback)
        host.NoteOnCallback.connect(self.slot_handleNoteOnCallback)
        host.NoteOffCallback.connect(self.slot_handleNoteOffCallback)
        host.PatchbayClientAddedCallback.connect(
            self.slot_handlePatchbayClientAddedCallback)
        host.PatchbayClientRemovedCallback.connect(
            self.slot_handlePatchbayClientRemovedCallback)
        host.PatchbayClientRenamedCallback.connect(
            self.slot_handlePatchbayClientRenamedCallback)
        host.PatchbayClientDataChangedCallback.connect(
            self.slot_handlePatchbayClientDataChangedCallback)
        host.PatchbayPortAddedCallback.connect(
            self.slot_handlePatchbayPortAddedCallback)
        host.PatchbayPortRemovedCallback.connect(
            self.slot_handlePatchbayPortRemovedCallback)
        host.PatchbayPortRenamedCallback.connect(
            self.slot_handlePatchbayPortRenamedCallback)
        host.PatchbayConnectionAddedCallback.connect(
            self.slot_handlePatchbayConnectionAddedCallback)
        host.PatchbayConnectionRemovedCallback.connect(
            self.slot_handlePatchbayConnectionRemovedCallback)

        if not doSetup: return

        parent.ui.act_plugins_enable.triggered.connect(self.slot_pluginsEnable)
        parent.ui.act_plugins_disable.triggered.connect(
            self.slot_pluginsDisable)
        parent.ui.act_plugins_volume100.triggered.connect(
            self.slot_pluginsVolume100)
        parent.ui.act_plugins_mute.triggered.connect(self.slot_pluginsMute)
        parent.ui.act_plugins_wet100.triggered.connect(self.slot_pluginsWet100)
        parent.ui.act_plugins_bypass.triggered.connect(self.slot_pluginsBypass)
        parent.ui.act_plugins_center.triggered.connect(self.slot_pluginsCenter)
        parent.ui.act_plugins_panic.triggered.connect(self.slot_pluginsDisable)

        parent.ui.act_canvas_show_internal.triggered.connect(
            self.slot_canvasShowInternal)
        parent.ui.act_canvas_show_external.triggered.connect(
            self.slot_canvasShowExternal)
        parent.ui.act_canvas_arrange.setEnabled(False)  # TODO, later
        parent.ui.act_canvas_arrange.triggered.connect(self.slot_canvasArrange)
        parent.ui.act_canvas_refresh.triggered.connect(self.slot_canvasRefresh)
        parent.ui.act_canvas_zoom_fit.triggered.connect(
            self.slot_canvasZoomFit)
        parent.ui.act_canvas_zoom_in.triggered.connect(self.slot_canvasZoomIn)
        parent.ui.act_canvas_zoom_out.triggered.connect(
            self.slot_canvasZoomOut)
        parent.ui.act_canvas_zoom_100.triggered.connect(
            self.slot_canvasZoomReset)
        parent.ui.act_canvas_print.triggered.connect(self.slot_canvasPrint)
        parent.ui.act_canvas_save_image.triggered.connect(
            self.slot_canvasSaveImage)

        parent.ui.act_settings_configure.triggered.connect(
            self.slot_configureCarla)

    # -----------------------------------------------------------------

    def getPluginEditDialog(self, pluginId):
        if pluginId >= self.fPluginCount:
            return None

        pedit = self.fPluginList[pluginId]
        if pedit is None:
            return None
        if False:
            pedit = DummyPluginEdit(self, 0)

        return pedit

    # -----------------------------------------------------------------

    @pyqtSlot(int, str)
    def slot_handlePluginAddedCallback(self, pluginId, pluginName):
        if self.fIsOnlyPatchbay:
            pedit = PluginEdit(self, self.host, pluginId)
        else:
            pedit = DummyPluginEdit(self, pluginId)

        self.fPluginList.append(pedit)
        self.fPluginCount += 1

        if self.fIsOnlyPatchbay and not self.fParent.isProjectLoading():
            self.host.set_active(pluginId, True)

    @pyqtSlot(int)
    def slot_handlePluginRemovedCallback(self, pluginId):
        patchcanvas.handlePluginRemoved(pluginId)

        if pluginId in self.fSelectedPlugins:
            self.clearSideStuff()

        pedit = self.getPluginEditDialog(pluginId)

        self.fPluginCount -= 1
        self.fPluginList.pop(pluginId)

        if pedit is not None:
            pedit.close()
            del pedit

        # push all plugins 1 slot back
        for i in range(pluginId, self.fPluginCount):
            pedit = self.fPluginList[i]
            pedit.setPluginId(i)

    @pyqtSlot(int, int, int, int)
    def slot_handleNoteOnCallback(self, pluginId, channel, note, velocity):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOn(note, False)

    @pyqtSlot(int, int, int)
    def slot_handleNoteOffCallback(self, pluginId, channel, note):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOff(note, False)

    # -----------------------------------------------------------------
    # HostWidgetMeta methods

    def removeAllPlugins(self):
        patchcanvas.handleAllPluginsRemoved()

        for pedit in self.fPluginList:
            if pedit is None:
                break
            pedit.close()
            del pedit

        self.fPluginCount = 0
        self.fPluginList = []

        self.clearSideStuff()

    def engineStarted(self):
        pass

    def engineStopped(self):
        patchcanvas.clear()

    def idleFast(self):
        if self.fPluginCount == 0:
            return

        for pluginId in self.fSelectedPlugins:
            self.fPeaksCleared = False
            if self.fPeaksIn.isVisible():
                self.fPeaksIn.displayMeter(
                    1, self.host.get_input_peak_value(pluginId, True))
                self.fPeaksIn.displayMeter(
                    2, self.host.get_input_peak_value(pluginId, False))
            if self.fPeaksOut.isVisible():
                self.fPeaksOut.displayMeter(
                    1, self.host.get_output_peak_value(pluginId, True))
                self.fPeaksOut.displayMeter(
                    2, self.host.get_output_peak_value(pluginId, False))
            return

        if self.fPeaksCleared:
            return

        self.fPeaksCleared = True
        self.fPeaksIn.displayMeter(1, 0.0, True)
        self.fPeaksIn.displayMeter(2, 0.0, True)
        self.fPeaksOut.displayMeter(1, 0.0, True)
        self.fPeaksOut.displayMeter(2, 0.0, True)

    def idleSlow(self):
        for pedit in self.fPluginList:
            if pedit is None:
                break
            pedit.idleSlow()

    def projectLoadingStarted(self):
        self.fView.setEnabled(False)

    def projectLoadingFinished(self):
        self.fView.setEnabled(True)
        QTimer.singleShot(1000, self.slot_canvasRefresh)

    def saveSettings(self, settings):
        settings.setValue("ShowMeters",
                          self.fParent.ui.act_settings_show_meters.isChecked())
        settings.setValue(
            "ShowKeyboard",
            self.fParent.ui.act_settings_show_keyboard.isChecked())
        settings.setValue("HorizontalScrollBarValue",
                          self.fView.horizontalScrollBar().value())
        settings.setValue("VerticalScrollBarValue",
                          self.fView.verticalScrollBar().value())

    def showEditDialog(self, pluginId):
        pedit = self.getPluginEditDialog(pluginId)

        if pedit:
            pedit.show()

    # -----------------------------------------------------------------
    # PluginEdit callbacks

    def editDialogVisibilityChanged(self, pluginId, visible):
        pass

    def editDialogPluginHintsChanged(self, pluginId, hints):
        pass

    def editDialogParameterValueChanged(self, pluginId, parameterId, value):
        pass

    def editDialogProgramChanged(self, pluginId, index):
        pass

    def editDialogMidiProgramChanged(self, pluginId, index):
        pass

    def editDialogNotePressed(self, pluginId, note):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOn(note, False)

    def editDialogNoteReleased(self, pluginId, note):
        if pluginId in self.fSelectedPlugins:
            self.fKeys.keyboard.sendNoteOff(note, False)

    def editDialogMidiActivityChanged(self, pluginId, onOff):
        pass

    # -----------------------------------------------------------------

    def clearSideStuff(self):
        self.scene.clearSelection()

        self.fSelectedPlugins = []

        self.fKeys.keyboard.allNotesOff(False)
        self.fKeys.setEnabled(False)

        self.fPeaksCleared = True
        self.fPeaksIn.displayMeter(1, 0.0, True)
        self.fPeaksIn.displayMeter(2, 0.0, True)
        self.fPeaksOut.displayMeter(1, 0.0, True)
        self.fPeaksOut.displayMeter(2, 0.0, True)

    def setupCanvas(self):
        pOptions = patchcanvas.options_t()
        pOptions.theme_name = self.fParent.fSavedSettings[
            CARLA_KEY_CANVAS_THEME]
        pOptions.auto_hide_groups = self.fParent.fSavedSettings[
            CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS]
        pOptions.use_bezier_lines = self.fParent.fSavedSettings[
            CARLA_KEY_CANVAS_USE_BEZIER_LINES]
        pOptions.antialiasing = self.fParent.fSavedSettings[
            CARLA_KEY_CANVAS_ANTIALIASING]
        pOptions.eyecandy = self.fParent.fSavedSettings[
            CARLA_KEY_CANVAS_EYE_CANDY]

        pFeatures = patchcanvas.features_t()
        pFeatures.group_info = False
        pFeatures.group_rename = False
        pFeatures.port_info = False
        pFeatures.port_rename = False
        pFeatures.handle_group_pos = True

        patchcanvas.setOptions(pOptions)
        patchcanvas.setFeatures(pFeatures)
        patchcanvas.init("Carla2", self.scene, canvasCallback, False)

        tryCanvasSize = self.fParent.fSavedSettings[
            CARLA_KEY_CANVAS_SIZE].split("x")

        if len(tryCanvasSize) == 2 and tryCanvasSize[0].isdigit(
        ) and tryCanvasSize[1].isdigit():
            self.fCanvasWidth = int(tryCanvasSize[0])
            self.fCanvasHeight = int(tryCanvasSize[1])
        else:
            self.fCanvasWidth = CARLA_DEFAULT_CANVAS_SIZE_WIDTH
            self.fCanvasHeight = CARLA_DEFAULT_CANVAS_SIZE_HEIGHT

        patchcanvas.setCanvasSize(0, 0, self.fCanvasWidth, self.fCanvasHeight)
        patchcanvas.setInitialPos(self.fCanvasWidth / 2,
                                  self.fCanvasHeight / 2)
        self.fView.setSceneRect(0, 0, self.fCanvasWidth, self.fCanvasHeight)

        self.themeData = [
            self.fCanvasWidth, self.fCanvasHeight,
            patchcanvas.canvas.theme.canvas_bg,
            patchcanvas.canvas.theme.rubberband_brush,
            patchcanvas.canvas.theme.rubberband_pen.color()
        ]

    def updateCanvasInitialPos(self):
        x = self.fView.horizontalScrollBar().value() + self.width() / 4
        y = self.fView.verticalScrollBar().value() + self.height() / 4
        patchcanvas.setInitialPos(x, y)

    # -----------------------------------------------------------------

    @pyqtSlot(bool)
    def slot_showCanvasMeters(self, yesNo):
        self.fPeaksIn.setVisible(yesNo)
        self.fPeaksOut.setVisible(yesNo)

    @pyqtSlot(bool)
    def slot_showCanvasKeyboard(self, yesNo):
        self.fKeys.setVisible(yesNo)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_miniCanvasCheckAll(self):
        self.slot_miniCanvasCheckSize()
        self.slot_horizontalScrollBarChanged(
            self.fView.horizontalScrollBar().value())
        self.slot_verticalScrollBarChanged(
            self.fView.verticalScrollBar().value())

    @pyqtSlot()
    def slot_miniCanvasCheckSize(self):
        self.fMiniCanvasPreview.setViewSize(
            float(self.width()) / self.fCanvasWidth,
            float(self.height()) / self.fCanvasHeight)

    @pyqtSlot(int)
    def slot_horizontalScrollBarChanged(self, value):
        if self.fMovingViaMiniCanvas: return

        maximum = self.fView.horizontalScrollBar().maximum()
        if maximum == 0:
            xp = 0
        else:
            xp = float(value) / maximum
        self.fMiniCanvasPreview.setViewPosX(xp)
        self.updateCanvasInitialPos()

    @pyqtSlot(int)
    def slot_verticalScrollBarChanged(self, value):
        if self.fMovingViaMiniCanvas: return

        maximum = self.fView.verticalScrollBar().maximum()
        if maximum == 0:
            yp = 0
        else:
            yp = float(value) / maximum
        self.fMiniCanvasPreview.setViewPosY(yp)
        self.updateCanvasInitialPos()

    @pyqtSlot()
    def slot_restoreScrollbarValues(self):
        settings = QSettings()
        self.fView.horizontalScrollBar().setValue(
            settings.value("HorizontalScrollBarValue",
                           self.fView.horizontalScrollBar().maximum() / 2,
                           type=int))
        self.fView.verticalScrollBar().setValue(
            settings.value("VerticalScrollBarValue",
                           self.fView.verticalScrollBar().maximum() / 2,
                           type=int))

    # -----------------------------------------------------------------

    @pyqtSlot(float)
    def slot_canvasScaleChanged(self, scale):
        self.fMiniCanvasPreview.setViewScale(scale)

    @pyqtSlot(int, int, QPointF)
    def slot_canvasItemMoved(self, group_id, split_mode, pos):
        self.fMiniCanvasPreview.update()

    @pyqtSlot(list)
    def slot_canvasPluginSelected(self, pluginList):
        self.fKeys.keyboard.allNotesOff(False)
        self.fKeys.setEnabled(
            len(pluginList) != 0)  # and self.fPluginCount > 0
        self.fSelectedPlugins = pluginList

    @pyqtSlot(float, float)
    def slot_miniCanvasMoved(self, xp, yp):
        self.fMovingViaMiniCanvas = True
        self.fView.horizontalScrollBar().setValue(
            xp * self.fView.horizontalScrollBar().maximum())
        self.fView.verticalScrollBar().setValue(
            yp * self.fView.verticalScrollBar().maximum())
        self.fMovingViaMiniCanvas = False
        self.updateCanvasInitialPos()

    # -----------------------------------------------------------------

    @pyqtSlot(int)
    def slot_noteOn(self, note):
        for pluginId in self.fSelectedPlugins:
            self.host.send_midi_note(pluginId, 0, note, 100)

            pedit = self.getPluginEditDialog(pluginId)
            pedit.noteOn(0, note, 100)

    @pyqtSlot(int)
    def slot_noteOff(self, note):
        for pluginId in self.fSelectedPlugins:
            self.host.send_midi_note(pluginId, 0, note, 0)

            pedit = self.getPluginEditDialog(pluginId)
            pedit.noteOff(0, note)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_pluginsEnable(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            self.host.set_active(i, True)

    @pyqtSlot()
    def slot_pluginsDisable(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            self.host.set_active(i, False)

    @pyqtSlot()
    def slot_pluginsVolume100(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_VOLUME:
                pedit.setParameterValue(PARAMETER_VOLUME, 1.0)
                self.host.set_volume(i, 1.0)

    @pyqtSlot()
    def slot_pluginsMute(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_VOLUME:
                pedit.setParameterValue(PARAMETER_VOLUME, 0.0)
                self.host.set_volume(i, 0.0)

    @pyqtSlot()
    def slot_pluginsWet100(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_DRYWET:
                pedit.setParameterValue(PARAMETER_DRYWET, 1.0)
                self.host.set_drywet(i, 1.0)

    @pyqtSlot()
    def slot_pluginsBypass(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_DRYWET:
                pedit.setParameterValue(PARAMETER_DRYWET, 0.0)
                self.host.set_drywet(i, 0.0)

    @pyqtSlot()
    def slot_pluginsCenter(self):
        if not self.host.is_engine_running():
            return

        for i in range(self.fPluginCount):
            pedit = self.fPluginList[i]
            if pedit is None:
                break

            if pedit.getHints() & PLUGIN_CAN_BALANCE:
                pedit.setParameterValue(PARAMETER_BALANCE_LEFT, -1.0)
                pedit.setParameterValue(PARAMETER_BALANCE_RIGHT, 1.0)
                self.host.set_balance_left(i, -1.0)
                self.host.set_balance_right(i, 1.0)

            if pedit.getHints() & PLUGIN_CAN_PANNING:
                pedit.setParameterValue(PARAMETER_PANNING, 0.0)
                self.host.set_panning(i, 0.0)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_configureCarla(self):
        dialog = CarlaSettingsW(self, self.host, True, hasGL)
        if not dialog.exec_():
            return

        self.fParent.loadSettings(False)

        patchcanvas.clear()

        self.setupCanvas()
        self.fParent.updateContainer(self.themeData)
        self.slot_miniCanvasCheckAll()

        if self.host.is_engine_running():
            self.host.patchbay_refresh(self.fExternalPatchbay)

    # -----------------------------------------------------------------

    @pyqtSlot(int, int, int, str)
    def slot_handlePatchbayClientAddedCallback(self, clientId, clientIcon,
                                               pluginId, clientName):
        pcSplit = patchcanvas.SPLIT_UNDEF
        pcIcon = patchcanvas.ICON_APPLICATION

        if clientIcon == PATCHBAY_ICON_PLUGIN:
            pcIcon = patchcanvas.ICON_PLUGIN
        if clientIcon == PATCHBAY_ICON_HARDWARE:
            pcIcon = patchcanvas.ICON_HARDWARE
        elif clientIcon == PATCHBAY_ICON_CARLA:
            pass
        elif clientIcon == PATCHBAY_ICON_DISTRHO:
            pcIcon = patchcanvas.ICON_DISTRHO
        elif clientIcon == PATCHBAY_ICON_FILE:
            pcIcon = patchcanvas.ICON_FILE

        patchcanvas.addGroup(clientId, clientName, pcSplit, pcIcon)

        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

        if pluginId < 0:
            return
        if pluginId >= self.fPluginCount:
            print("sorry, can't map this plugin to canvas client", pluginId,
                  self.fPluginCount)
            return

        patchcanvas.setGroupAsPlugin(
            clientId, pluginId,
            bool(
                self.host.get_plugin_info(pluginId)['hints']
                & PLUGIN_HAS_CUSTOM_UI))

    @pyqtSlot(int)
    def slot_handlePatchbayClientRemovedCallback(self, clientId):
        #if not self.fEngineStarted: return
        patchcanvas.removeGroup(clientId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, str)
    def slot_handlePatchbayClientRenamedCallback(self, clientId,
                                                 newClientName):
        patchcanvas.renameGroup(clientId, newClientName)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, int)
    def slot_handlePatchbayClientDataChangedCallback(self, clientId,
                                                     clientIcon, pluginId):
        pcIcon = patchcanvas.ICON_APPLICATION

        if clientIcon == PATCHBAY_ICON_PLUGIN:
            pcIcon = patchcanvas.ICON_PLUGIN
        if clientIcon == PATCHBAY_ICON_HARDWARE:
            pcIcon = patchcanvas.ICON_HARDWARE
        elif clientIcon == PATCHBAY_ICON_CARLA:
            pass
        elif clientIcon == PATCHBAY_ICON_DISTRHO:
            pcIcon = patchcanvas.ICON_DISTRHO
        elif clientIcon == PATCHBAY_ICON_FILE:
            pcIcon = patchcanvas.ICON_FILE

        patchcanvas.setGroupIcon(clientId, pcIcon)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

        if pluginId < 0:
            return
        if pluginId >= self.fPluginCount:
            print("sorry, can't map this plugin to canvas client", pluginId,
                  self.fPluginCount)
            return

        patchcanvas.setGroupAsPlugin(
            clientId, pluginId,
            bool(
                self.host.get_plugin_info(pluginId)['hints']
                & PLUGIN_HAS_CUSTOM_UI))

    @pyqtSlot(int, int, int, str)
    def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portFlags,
                                             portName):
        isAlternate = False

        if (portFlags & PATCHBAY_PORT_IS_INPUT):
            portMode = patchcanvas.PORT_MODE_INPUT
        else:
            portMode = patchcanvas.PORT_MODE_OUTPUT

        if (portFlags & PATCHBAY_PORT_TYPE_AUDIO):
            portType = patchcanvas.PORT_TYPE_AUDIO_JACK
        elif (portFlags & PATCHBAY_PORT_TYPE_CV):
            isAlternate = True
            portType = patchcanvas.PORT_TYPE_AUDIO_JACK
        elif (portFlags & PATCHBAY_PORT_TYPE_MIDI):
            portType = patchcanvas.PORT_TYPE_MIDI_JACK
        else:
            portType = patchcanvas.PORT_TYPE_NULL

        patchcanvas.addPort(clientId, portId, portName, portMode, portType,
                            isAlternate)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int)
    def slot_handlePatchbayPortRemovedCallback(self, groupId, portId):
        #if not self.fEngineStarted: return
        patchcanvas.removePort(groupId, portId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, str)
    def slot_handlePatchbayPortRenamedCallback(self, groupId, portId,
                                               newPortName):
        patchcanvas.renamePort(groupId, portId, newPortName)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, int, int, int)
    def slot_handlePatchbayConnectionAddedCallback(self, connectionId,
                                                   groupOutId, portOutId,
                                                   groupInId, portInId):
        patchcanvas.connectPorts(connectionId, groupOutId, portOutId,
                                 groupInId, portInId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    @pyqtSlot(int, int, int)
    def slot_handlePatchbayConnectionRemovedCallback(self, connectionId,
                                                     portOutId, portInId):
        #if not self.fEngineStarted: return
        patchcanvas.disconnectPorts(connectionId)
        QTimer.singleShot(0, self.fMiniCanvasPreview.update)

    # -----------------------------------------------------------------

    @pyqtSlot()
    def slot_canvasArrange(self):
        patchcanvas.arrange()

    @pyqtSlot()
    def slot_canvasShowInternal(self):
        self.fExternalPatchbay = False
        self.fParent.ui.act_canvas_show_internal.blockSignals(True)
        self.fParent.ui.act_canvas_show_external.blockSignals(True)
        self.fParent.ui.act_canvas_show_internal.setChecked(True)
        self.fParent.ui.act_canvas_show_external.setChecked(False)
        self.fParent.ui.act_canvas_show_internal.blockSignals(False)
        self.fParent.ui.act_canvas_show_external.blockSignals(False)
        self.slot_canvasRefresh()

    @pyqtSlot()
    def slot_canvasShowExternal(self):
        self.fExternalPatchbay = True
        self.fParent.ui.act_canvas_show_internal.blockSignals(True)
        self.fParent.ui.act_canvas_show_external.blockSignals(True)
        self.fParent.ui.act_canvas_show_internal.setChecked(False)
        self.fParent.ui.act_canvas_show_external.setChecked(True)
        self.fParent.ui.act_canvas_show_internal.blockSignals(False)
        self.fParent.ui.act_canvas_show_external.blockSignals(False)
        self.slot_canvasRefresh()

    @pyqtSlot()
    def slot_canvasRefresh(self):
        patchcanvas.clear()

        if self.host.is_engine_running():
            self.host.patchbay_refresh(self.fExternalPatchbay)

            for pedit in self.fPluginList:
                if pedit is None:
                    break
                pedit.reloadAll()

        QTimer.singleShot(
            1000 if self.fParent.fSavedSettings[CARLA_KEY_CANVAS_EYE_CANDY]
            else 0, self.fMiniCanvasPreview.update)

    @pyqtSlot()
    def slot_canvasZoomFit(self):
        self.scene.zoom_fit()

    @pyqtSlot()
    def slot_canvasZoomIn(self):
        self.scene.zoom_in()

    @pyqtSlot()
    def slot_canvasZoomOut(self):
        self.scene.zoom_out()

    @pyqtSlot()
    def slot_canvasZoomReset(self):
        self.scene.zoom_reset()

    @pyqtSlot()
    def slot_canvasPrint(self):
        self.scene.clearSelection()
        self.fExportPrinter = QPrinter()
        dialog = QPrintDialog(self.fExportPrinter, self)

        if dialog.exec_():
            painter = QPainter(self.fExportPrinter)
            painter.save()
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setRenderHint(QPainter.TextAntialiasing)
            self.scene.render(painter)
            painter.restore()

    @pyqtSlot()
    def slot_canvasSaveImage(self):
        newPath = QFileDialog.getSaveFileName(
            self,
            self.tr("Save Image"),
            filter=self.tr("PNG Image (*.png);;JPEG Image (*.jpg)"))

        if config_UseQt5:
            newPath = newPath[0]
        if not newPath:
            return

        self.scene.clearSelection()

        if newPath.lower().endswith((".jpg", )):
            imgFormat = "JPG"
        elif newPath.lower().endswith((".png", )):
            imgFormat = "PNG"
        else:
            # File-dialog may not auto-add the extension
            imgFormat = "PNG"
            newPath += ".png"

        self.fExportImage = QImage(self.scene.sceneRect().width(),
                                   self.scene.sceneRect().height(),
                                   QImage.Format_RGB32)
        painter = QPainter(self.fExportImage)
        painter.save()
        painter.setRenderHint(
            QPainter.Antialiasing)  # TODO - set true, cleanup this
        painter.setRenderHint(QPainter.TextAntialiasing)
        self.scene.render(painter)
        self.fExportImage.save(newPath, imgFormat, 100)
        painter.restore()

    # -----------------------------------------------------------------

    def resizeEvent(self, event):
        QFrame.resizeEvent(self, event)
        self.slot_miniCanvasCheckSize()
Example #9
0
class analysis(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.show()

    def initUI(self):
        # 设置菜单并获取日期列表
        self.loadMenu()
        # 加载初始化数据
        self.load_initial_data()
        #设置提示信息字体
        ##
        # 整体布局为水平布局
        self.centralWidget = QWidget(self)
        self.upest = QHBoxLayout()
        self.setScrollArea()
        self.setPie()  # 右

        self.centralWidget.setLayout(self.upest)
        self.setCentralWidget(self.centralWidget)

        #图标
        self.setIcon()

        #页面设置
        self.SetWindoww()

    def loadMenu(self):
        #从数据库读取日期信息
        if not path.isfile('./data/date_list'):
            system('copy nul date_list')
            print('not exist')
        else:
            print('exists!')

        with open('./data/date_list', 'r') as f:
            self.date_list = [x.strip() for x in f.readlines()]

        print(self.date_list)
        #self.date_list = ['2019/5/16','2019/5/17']
        menu = self.menuBar()
        item = menu.addMenu('&日期选择')
        for i in self.date_list:
            ac = QAction(i, self)
            ac.triggered.connect(self.redraw)
            item.addAction(ac)

    def load_initial_data(self):
        def filter_date(date_list, date):
            return [x for x in date_list if x['phase'][0] == date]

        self.colors = [
            '#90ed7d', '#f7a35c', '#f15c80', '#7199cf', '#4fc4aa', '#ffff10'
        ]
        #self.colors = ['#90ed7d', '#f7a35c', '#f15c80']
        if not self.date_list:
            self.initial_timeline = []
            self.initial_pie = {}
            self.date_list = ['没有任务记录~']
            return

        with open('./data/tasks', 'r') as f:
            tasks_to_show = filter_date(
                [loads(x.strip('\n')) for x in f.readlines()],
                self.date_list[-1])

        #print(tasks_to_show)
        #从数据库获取最新一天的数据
        # tasks_to_show = [
        #     {'title': '程设', 'phase': ('2019/5/31', '0:00', '0:30'), 'tags': '学习'},
        #     {'title': '打游戏', 'phase': ('2019/5/31', '0:30', '1:00'), 'tags': '娱乐'},
        #     {'title': '打篮球', 'phase': ('2019/5/31', '18:00', '19:15'), 'tags': '运动'}
        # ]
        self.initial_timeline = tasks_to_show
        #self.initial_timeline = []
        self.initial_pie = [(x['tags'],
                             self.time_len([x['phase'][1], x['phase'][2]]))
                            for x in tasks_to_show]
        print('inital pie data is {}'.format(self.initial_pie))
        #self.initial_pie = []
        test = [{
            'title': '程设',
            'phase': ('2019/5/28', '8:00', '10:50'),
            'tags': '测试0'
        }, {
            'title': '打游戏',
            'phase': ('2019/5/28', '1:30', '4:20'),
            'tags': '测试1'
        }, {
            'title': '打篮球',
            'phase': ('2019/5/28', '18:00', '19:15'),
            'tags': '测试2'
        }]

        #self.test = {x['tags']:self.time_len([x['phase'][1], x['phase'][2]]) for x in test}
        self.test = test

    def time_len(self, time_points):
        #计算两个字符串格式日期的时间间隔 按分钟计
        t1 = time_points[0].split(':')
        t2 = time_points[1].split(':')
        t1 = [int(x) for x in t1]
        t2 = [int(x) for x in t2]
        return 60 * (t2[0] - 1 - t1[0]) + 60 + t2[1] - t1[1]

    def time_transform(self, tbegin, tend):
        t1 = tbegin.split(':')
        t2 = tend.split(':')
        t1 = [int(x) for x in t1]
        t2 = [int(x) for x in t2]
        return t1[0] * 60 + t1[1], t2[0] * 60 + t2[1]

    def redraw(self):
        def filter_date(date_list, date):
            return [x for x in date_list if x['phase'][0] == date]

        date_to_show = self.sender().text()
        #从数据库提取指定日期的任务列表,每个元素是一个字典
        tasks_to_show = [{
            'title': '程设',
            'phase': ('2019/5/17', '8:00', '10:20'),
            'tags': '你好'
        }, {
            'title': '打游戏',
            'phase': ('2019/5/17', '1:30', '4:20'),
            'tags': '娱乐'
        }, {
            'title': '打篮球',
            'phase': ('2019/5/17', '18:00', '19:15'),
            'tags': '运动'
        }]

        with open('./data/tasks', 'r') as f:
            tasks_to_show = filter_date(
                [loads(x.strip('\n')) for x in f.readlines()], date_to_show)
        #draw new pie
        pie_data = [(x['tags'], self.time_len([x['phase'][1], x['phase'][2]]))
                    for x in tasks_to_show]
        print('pie data is {}'.format(pie_data))
        self.draw_pie(pie_data, date_to_show)
        self.draw_timeline(tasks_to_show)
        #draw new timeline

    def draw_pie(self, data, today):
        # if not data:
        #     return
        def sum_data(data):
            res = {}
            for x in data:
                res[x[0]] = 0
            for x in data:
                res[x[0]] += x[1]
            return res

        data = sum_data(data)
        print('new pie data is {}'.format(data))
        self.F = MyFigure(width=3, height=2)

        values = [x for x in data.values()]
        labels = [x for x in data.keys()]
        #colors = ['#7199cf', '#4fc4aa', '#ffff10']
        colors_sample = []
        for i in range(len(values)):
            colors_sample.append(self.colors[i % len(self.colors)])
        print(colors_sample)
        # 设置饼图的凸出显示
        explode = [0 for i in range(len(values))]
        self.F.axes.pie(values,
                        labels=labels,
                        colors=colors_sample,
                        explode=explode,
                        shadow=False)
        self.F.fig.suptitle(today)

        # graphicscene是一个展示2D图形的场景,setSceneRect的效果是设置场景中可见的矩形范围
        # 参数a b c d; a是可见范围左上角坐标的横坐标 b是纵坐标; c是可见范围的横向距离,d是纵向距离
        # graphicscene.setSceneRect(QtCore.QRectF(101, 300, 590, 100))
        graphicscene = QGraphicsScene()
        graphicscene.addWidget(self.F)
        graphicscene.setSceneRect(QRectF(101, 300, 590, 100))
        self.graphicview.setScene(graphicscene)

    def draw_timeline(self, data):
        def sort_func(elem):
            t = elem['phase'][1].split(':')
            t = [int(x) for x in t]
            return 60 * t[0] + t[1]

        for i in range(self.vlay_2.count()):
            self.vlay_2.itemAt(i).widget().deleteLater()

        if not data:
            temp = QLabel("还没有任务完成~", self)
            temp.setStyleSheet(
                'background-color: red; margin: 0px; font-size:20px;color:black'
            )
            temp.setFixedHeight(60)
            temp.setFixedWidth(345)
            self.vlay_2.addWidget(temp)
            self.vlay_2.addWidget(QLabel())
            return

        #数据项x格式  {'title': '程设', 'phase': ('2019/5/17', '8:00', '10:50'), 'tags': '学习'},
        data.sort(key=sort_func)
        print(data)
        index = -1
        head_time = 0
        for x in data:
            index += 1
            temp = QLabel(x['title'], self)
            temp.setToolTip('标签:{}\n时间:{} ~ {}'.format(x['tags'],
                                                       x['phase'][1],
                                                       x['phase'][2]))
            begin_point, end_point = self.time_transform(
                x['phase'][1], x['phase'][2])

            if head_time != begin_point:
                blank = QLabel('none', self)
                #blank.setStyleSheet('margin: 0px; font-size:20px;color:black')
                #blank.setStyleSheet('background-color: purple; margin: 0px; font-size:20px;color:black')
                blank.setFixedWidth(345)
                if begin_point <= head_time:
                    print('error!!!')
                blank.setFixedHeight(2 * (begin_point - head_time))
                #blank.setFixedHeight(100)

                self.vlay_2.addWidget(blank)
                head_time = end_point
                print(index)
            else:
                head_time = end_point
            temp.setStyleSheet(
                "background-color: {}; margin: 0px; font-size:20px;color:black"
                .format(self.colors[index % len(self.colors)]))
            #temp.setStyleSheet("background-color: rgb(144,237,15); margin: 0px; font-size:20px;color:black")
            temp.setFixedWidth(345)
            temp.setFixedHeight(2 * (end_point - begin_point))
            self.vlay_2.addWidget(temp)
        self.vlay_2.addWidget(QLabel())

    def setScrollArea(self):
        self.scrollArea = QScrollArea(self)
        self.upest.addWidget(self.scrollArea)
        self.scrollArea.resize(1000, 1000)
        self.scrollcontent = QWidget()
        self.setMinimumHeight(10)  ###important

        self.lay1 = QHBoxLayout(self)
        self.lay1.setContentsMargins(0, 0, 0, 0)
        self.lay1.setSpacing(0)

        self.vlay_1 = QVBoxLayout(self)
        self.vlay_1.setContentsMargins(0, 0, 0, 0)
        self.vlay_1.setSpacing(0)

        self.vlay_2 = QVBoxLayout(self)
        self.vlay_2.setContentsMargins(0, 0, 0, 0)
        self.vlay_2.setSpacing(0)
        for i in range(24):
            temp = QLabel("{}:00~{}:00".format(str(i), str(i + 1)))
            if i % 2 == 0:
                temp.setStyleSheet(
                    'background-color: rgb(240, 248, 255); margin: 0px; font-size:20px;color:black'
                )
                # temp.setStyleSheet('margin: 0px; border:2px solid red; border-left: 0px; font-size:20px;color:black')
            else:
                #rgb(232, 234, 212)
                temp.setStyleSheet(
                    'background-color: rgb(230, 230, 250); margin: 0px; font-size:20px;color:black'
                )
            temp.setFixedHeight(120)
            temp.setFixedWidth(200)
            self.vlay_1.addWidget(temp)

        self.vlay_1.addWidget(QLabel())
        self.draw_timeline(self.initial_timeline)

        self.lay1.addLayout(self.vlay_1)
        self.lay1.addLayout(self.vlay_2)
        self.scrollcontent.setLayout(self.lay1)
        self.scrollArea.setWidget(self.scrollcontent)

    def setPie(self):
        self.graphicview = QGraphicsView()
        self.graphicview.horizontalScrollBar().setVisible(False)
        self.draw_pie(self.initial_pie, self.date_list[-1])
        self.graphicview.show()
        self.upest.addWidget(self.graphicview)

    def setIcon(self):
        self.setWindowIcon(QIcon('./images/others/icon.png'))

    def SetWindoww(self):
        self.move(403, 36)
        #self.resize(1200,900)
        self.setFixedSize(1200, 900)
        self.setWindowTitle('觅时')


# if __name__ == '__main__':
#     app = QApplication(argv)
#     w = main()
#     exit(app.exec_())