Exemplo n.º 1
0
    def _cfg_action(
        self,
        menu,
        title,
        setting,
        icon=None,
        shortcut=None
    ):

        action = QAction(title, self)
        if icon:
            action.setIcon(self._ide.theme.qicon(icon))
        if shortcut:
            action.setShortcut(shortcut)
            action.setToolTip(
                u'{} ({})'.format(title.replace(u'&', u''), shortcut)
            )
        
        def change_setting(value):
            self._ide.extension_manager.fire(
                'setting_changed',
                setting=setting,
                value=value
            )
            
        action.triggered.connect(change_setting)
        action.setCheckable(True)
        action.setChecked(cfg[setting])
        action.setPriority(QAction.HighPriority)
        menu.addAction(action)
        self._cfg_actions[setting] = action
        return action
Exemplo n.º 2
0
 def _add_legend_toggle_action(self, menu, event):
     legend = event.inaxes.axes.get_legend()
     legend_action = QAction("Show legend", menu, checkable=True)
     legend_action.setChecked(legend is not None and legend.get_visible())
     legend_action.toggled.connect(
         lambda: self._toggle_legend_and_redraw(event.inaxes.axes))
     menu.addAction(legend_action)
Exemplo n.º 3
0
    def menu_actions(self):
        """
        List of QtWidgets.QActions to be attached to this tool
        as a context menu.
        """
        self.options = []

        component_action_group = QActionGroup(self.tool_bar)

        action = QAction("Off", self.tool_bar, checkable=True)
        action.setChecked(True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.remove_contour)
        self.options.append(action)

        action = QAction("Current Component", self.tool_bar, checkable=True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.default_contour)
        self.options.append(action)

        action = QAction("Custom Component", self.tool_bar, checkable=True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.custom_contour)
        self.options.append(action)

        action = QAction(" ", self.tool_bar)
        action.setSeparator(True)
        self.options.append(action)

        action = QAction("Contour Settings", self.tool_bar)
        action.triggered.connect(self.viewer.edit_contour_settings)
        self.options.append(action)

        return self.options
Exemplo n.º 4
0
    def customMenuRequested(self, position):
        """Builds a custom menu for items items"""
        index = self.indexAt(position)  # type: QModelIndex
        menu = QMenu(self)

        if index.isValid():

            if index.data(EnsembleModel.data_type_role
                          ) == WorkspaceDataType.Ensemble:

                # Allow renaming the ensemble via the context menu
                rename_action = QAction("Rename Collection", menu)
                rename_action.triggered.connect(self._rename_action)
                menu.addAction(rename_action)

                # Allow toggling the active ensemble via the context menu
                # * there can only be at most 1 active ensemble
                # * there are only 0 active ensembles when data has not yet been loaded ???
                # * opening data updates the active ensemble to that data
                is_active = index.data(EnsembleModel.active_role)
                active_text = "Active"
                toggle_active_action = QAction(active_text, menu)
                toggle_active_action.setCheckable(True)
                if is_active is True:
                    toggle_active_action.setChecked(True)
                else:
                    toggle_active_action.setChecked(False)
                    toggle_active_action.setText(f"Not {active_text}")

                # Make sure to update the model with the active / deactivated ensemble
                toggle_active_action.toggled.connect(self._set_active_action)
                # Don't allow deactivating the active ensemble if there is only one loaded
                if self.model().rowCount() == 1:
                    toggle_active_action.setEnabled(False)
                menu.addAction(toggle_active_action)

                menu.addSeparator()

            remove_text = "Remove "
            data_type_role = index.data(EnsembleModel.data_type_role)
            if data_type_role == WorkspaceDataType.Ensemble:
                remove_text += "Ensemble"
            elif data_type_role == WorkspaceDataType.Catalog:
                remove_text += "Catalog"
            elif data_type_role == WorkspaceDataType.Intent:
                remove_text += "Item"
            remove_action = QAction(remove_text, menu)
            remove_action.triggered.connect(self._remove_action)
            menu.addAction(remove_action)

        else:
            create_ensemble_action = QAction("Create New Collection", menu)
            create_ensemble_action.triggered.connect(
                self._create_ensemble_action)
            menu.addAction(create_ensemble_action)

        # Display menu wherever the user right-clicked
        menu.popup(self.viewport().mapToGlobal(position))
Exemplo n.º 5
0
    def __init__(self, parent=None, standalone=False):
        super(Camera, self).__init__(parent)

        # This prevents doing unneeded initialization
        # when QtDesginer loads the plugin.
        if parent is None and not standalone:
            return

        if not multimedia_available:
            return

        self.ui = uic.loadUi(os.path.join(WIDGET_PATH, "camera.ui"), self)

        self.camera = None
        self.imageCapture = None
        self.mediaRecorder = None
        self.isCapturingImage = False
        self.applicationExiting = False

        self.imageSettings = QImageEncoderSettings()
        self.audioSettings = QAudioEncoderSettings()
        self.videoSettings = QVideoEncoderSettings()
        self.videoContainerFormat = ''

        camera_device = QByteArray()

        videoDevicesGroup = QActionGroup(self)

        videoDevicesGroup.setExclusive(True)

        if not QCamera.availableDevices():
            self.ui.devicesCombo.addItem("No Device")
        else:
            for deviceName in QCamera.availableDevices():
                description = QCamera.deviceDescription(deviceName)
                self.ui.devicesCombo.addItem(description)

                videoDeviceAction = QAction(description, videoDevicesGroup)
                videoDeviceAction.setCheckable(True)
                videoDeviceAction.setData(deviceName)

                if camera_device.isEmpty():
                    cameraDevice = deviceName
                    videoDeviceAction.setChecked(True)

                self.ui.devicesCombo.addAction(videoDeviceAction)

        videoDevicesGroup.triggered.connect(self.updateCameraDevice)

        self.ui.captureWidget.currentChanged.connect(self.updateCaptureMode)

        self.ui.devicesCombo.currentIndexChanged.connect(self.get_device_action)

        self.ui.lockButton.hide()
        
        if not IN_DESIGNER:
            # Start camera 2s after the UI has loaded
            QTimer.singleShot(2000, lambda: self.setCamera(camera_device))
Exemplo n.º 6
0
    def _init_menu_buttons(self):
        """
        Add the two menu buttons to the tool bar. Currently two are defined:
            View - for changing the view of the active window
            Data Processing - for applying a data processing step to the data.

        :return:
        """
        self._option_buttons = [
            self.ui.view_option_button, self.ui.cube_option_button
        ]

        # Create the View Menu
        view_menu = self._dict_to_menu(
            OrderedDict([
                ('Hide Axes', ['checkable', self._toggle_viewer_axes]),
                ('Hide Toolbars', ['checkable', self._toggle_toolbars]),
                ('Hide Spaxel Value Tooltip',
                 ['checkable', self._toggle_hover_value]),
                ('Hide Stats', ['checkable', self._toggle_stats_display]),
                ('Convert Flux Units',
                 lambda: self._open_dialog('Convert Flux Units', None)),
                ('Wavelength Units/Redshift',
                 lambda: self._open_dialog('Wavelength Units/Redshift', None))
            ]))

        # Add toggle RA-DEC format:
        format_menu = view_menu.addMenu("RA-DEC Format")
        format_action_group = QActionGroup(format_menu)
        self.ra_dec_format_menu = format_menu

        # Make sure to change all instances of the the names
        # of the formats if modifications are made to them.
        for format_name in ["Sexagesimal", "Decimal Degrees"]:
            act = QAction(format_name, format_menu)
            act.triggered.connect(self._toggle_all_coords_in_degrees)
            act.setActionGroup(format_action_group)
            act.setCheckable(True)
            act.setChecked(
                True) if format == "Sexagesimal" else act.setChecked(False)
            format_menu.addAction(act)

        self.ui.view_option_button.setMenu(view_menu)

        # Create the Data Processing Menu
        cube_menu = self._dict_to_menu(
            OrderedDict([
                ('Collapse Cube',
                 lambda: self._open_dialog('Collapse Cube', None)),
                ('Spatial Smoothing',
                 lambda: self._open_dialog('Spatial Smoothing', None)),
                ('Moment Maps',
                 lambda: self._open_dialog('Moment Maps', None)),
                ('Arithmetic Operations',
                 lambda: self._open_dialog('Arithmetic Operations', None))
            ]))
        self.ui.cube_option_button.setMenu(cube_menu)
Exemplo n.º 7
0
    def _init_menu_buttons(self):
        """
        Add the two menu buttons to the tool bar. Currently two are defined:
            View - for changing the view of the active window
            Data Processing - for applying a data processing step to the data.

        :return:
        """
        self._option_buttons = [
            self.ui.view_option_button,
            self.ui.cube_option_button
        ]

        # Create the View Menu
        view_menu = self._dict_to_menu(OrderedDict([
            ('Hide Axes', ['checkable', self._toggle_viewer_axes]),
            ('Hide Toolbars', ['checkable', self._toggle_toolbars]),
            ('Hide Spaxel Value Tooltip', ['checkable', self._toggle_hover_value]),
            ('Hide Stats', ['checkable', self._toggle_stats_display]),
            ('Flux Units', OrderedDict([
                ('Convert Displayed Units', lambda: self._open_dialog('Convert Displayed Units', None)),
                ('Convert Data Values', lambda: self._open_dialog('Convert Data Values', None)),
                ])
             ),
            ('Wavelength Units/Redshift', lambda: self._open_dialog('Wavelength Units/Redshift', None))
        ]))

        # Add toggle RA-DEC format:
        format_menu = view_menu.addMenu("RA-DEC Format")
        format_action_group = QActionGroup(format_menu)
        self.ra_dec_format_menu = format_menu

        # Make sure to change all instances of the the names
        # of the formats if modifications are made to them.
        for format_name in ["Sexagesimal", "Decimal Degrees"]:
            act = QAction(format_name, format_menu)
            act.triggered.connect(self._toggle_all_coords_in_degrees)
            act.setActionGroup(format_action_group)
            act.setCheckable(True)
            act.setChecked(True) if format == "Sexagesimal" else act.setChecked(False)
            format_menu.addAction(act)

        self.ui.view_option_button.setMenu(view_menu)

        # Create the Data Processing Menu
        cube_menu = self._dict_to_menu(OrderedDict([
            ('Collapse Cube', lambda: self._open_dialog('Collapse Cube', None)),
            ('Spatial Smoothing', lambda: self._open_dialog('Spatial Smoothing', None)),
            ('Moment Maps', lambda: self._open_dialog('Moment Maps', None)),
            ('Arithmetic Operations', lambda: self._open_dialog('Arithmetic Operations', None))
        ]))
        self.ui.cube_option_button.setMenu(cube_menu)
Exemplo n.º 8
0
    def getContextMenus(self, event=None):
        """Get context menus.

        Args:
          event: DESCRIPTION. Defaults to None.

        """
        if self.menu is None:
            self.menu = QMenu()
            self.menu.setTitle(self.name + " options..")

            view_all = QAction("View all", self.menu)
            view_all.triggered.connect(self.view_all)
            self.menu.addAction(view_all)
            self.menu.view_all = view_all

            toggle_aspect_mode = QAction("Locked aspect",
                                         self.menu,
                                         checkable=True)
            toggle_aspect_mode.triggered.connect(self.toggle_aspect_mode)
            toggle_aspect_mode.setChecked(True)
            self.menu.addAction(toggle_aspect_mode)
            self.menu.toggle_aspect_mode = toggle_aspect_mode

            toggle_click_mode = QAction(
                "Mouse panmode",
                self.menu,
                shortcut=QKeySequence("Shift+S"),
                checkable=True,
            )
            toggle_click_mode.triggered.connect(self.toggle_mouse_mode)
            self.menu.addAction(toggle_click_mode)
            self.menu.toggle_mode = toggle_click_mode

            export_view = QAction("Export View", self.menu)
            export_view.setToolTip("Axis와 Marker를 포함한 화면을 캡쳐한다.")
            export_view.triggered.connect(self.export_view_clicked)
            self.menu.addAction(export_view)

            export_img = QAction("Export data as png", self.menu)
            export_img.setToolTip("Imagesc의 Data 원본을 Image 파일로 저장한다.")
            export_img.triggered.connect(self.export_data_as_img_clicked)
            self.menu.addAction(export_img)

        if self.view.vb.state["mouseMode"] == self.view.vb.PanMode:
            self.menu.toggle_mode.setChecked(True)
        else:
            self.menu.toggle_mode.setChecked(False)

        return self.menu
Exemplo n.º 9
0
 def patternMenu(self, menu, node):
     a = QAction("Recursive sub-pattern add", self, checkable=True)
     menu.addAction(a)
     a.setChecked(self._recursiveAddNewNode)
     menu.addSeparator()
     for t in [n[0] for n in CGU.getAuthChildren(node)]:
         def genCopyPattern(arg):
             def copyPattern():
                 self.model().copyNodeRaw(CGS.profile[arg][0])
                 if (self.getLastEntered() is not None):
                     self.model().pasteAsChild(self.getLastEntered())
             return copyPattern
         a = QAction("{}".format(t), self, triggered=genCopyPattern(t))
         menu.addAction(a)
Exemplo n.º 10
0
class Viewer(ViewerModel):
    """
    This extends the model by attaching a Qt Window as its view.

    This object is meant to be exposed to the user in an interactive console.
    """
    def __init__(self, *, show=True, title="Demo App"):
        # TODO Where does title thread through?
        super().__init__()

        self._widget = QtViewer(self)
        self._window = Window(self._widget, show=show)

        menu_bar = self._window._qt_window.menuBar()
        menu_item_control = menu_bar.addMenu("Control Actions")
        self.action_activate_env_destroy = QAction(
            "Activate 'Destroy Environment'", self._window._qt_window)
        self.action_activate_env_destroy.setCheckable(True)
        self._update_action_env_destroy_state()
        self.action_activate_env_destroy.triggered.connect(
            self._activate_env_destroy_triggered)
        menu_item_control.addAction(self.action_activate_env_destroy)

        self._widget.model.run_engine.events.status_changed.connect(
            self.on_update_widgets)

    def _update_action_env_destroy_state(self):
        env_destroy_activated = self._widget.model.run_engine.env_destroy_activated
        self.action_activate_env_destroy.setChecked(env_destroy_activated)

    def _activate_env_destroy_triggered(self):
        env_destroy_activated = self._widget.model.run_engine.env_destroy_activated
        self._widget.model.run_engine.activate_env_destroy(
            not env_destroy_activated)

    def on_update_widgets(self, event):
        self._update_action_env_destroy_state()

    @property
    def window(self):
        return self._window

    def show(self):
        """Resize, show, and raise the window."""
        self._window.show()

    def close(self):
        """Close the window."""
        self._window.close()
Exemplo n.º 11
0
    def __init__(self, entity, env):
        d = Diagram_Item(entity)
        d.modified_callback = self.set_modified
        super().__init__(d)
        self.modified_callback = env.set_modified
        self.entity = entity

        show_ports_action = QAction("Connection Ports", self)
        self._show_ports_action = show_ports_action
        show_ports_action.setStatusTip("Show connection ports when hovering")
        show_ports_action.setCheckable(True)
        show_ports_action.setChecked(False)
        show_ports_action.setIcon(QIcon.fromTheme("edit-find"))
        show_ports_action.triggered.connect(
            lambda x: d.set_show_connection_ports_on_hover(x))
        self.view_menu.addAction(show_ports_action)
        self.tools.append(show_ports_action)
Exemplo n.º 12
0
    def add_header_context_menu(self,
                                checked=None,
                                checkable=None,
                                enabled=None):
        """
        Adds the context menu from using header information

        checked can be a header_name -> boolean dictionary. If given, headers
        with the key name will get the checked value from the dictionary.
        The corresponding column will be hidden if checked is False.

        checkable can be a header_name -> boolean dictionary. If given, headers
        with the key name will get the checkable value from the dictionary.

        enabled can be a header_name -> boolean dictionary. If given, headers
        with the key name will get the enabled value from the dictionary.
        """
        checked = checked if checked is not None else {}
        checkable = checkable if checkable is not None else {}
        enabled = enabled if enabled is not None else {}

        horizontal_header = self._horizontal_header()
        horizontal_header.setContextMenuPolicy(Qt.ActionsContextMenu)

        self.toggle_column_actions_group = QActionGroup(self)
        self.toggle_column_actions_group.setExclusive(False)
        self.__toggle_functions = []  # for keeping references

        for col in range(horizontal_header.count()):
            column_label = self.model().headerData(col, Qt.Horizontal,
                                                   Qt.DisplayRole)
            logger.debug("Adding: col {}: {}".format(col, column_label))
            action = QAction(str(column_label),
                             self.toggle_column_actions_group,
                             checkable=checkable.get(column_label, True),
                             enabled=enabled.get(column_label, True),
                             toolTip=_("Shows or hides "
                                       "the {} column").format(column_label))
            func = self.__make_show_column_function(col)
            self.__toggle_functions.append(func)  # keep reference
            horizontal_header.addAction(action)
            is_checked = checked.get(
                column_label, not horizontal_header.isSectionHidden(col))
            horizontal_header.setSectionHidden(col, not is_checked)
            action.setChecked(is_checked)
            action.toggled.connect(func)
Exemplo n.º 13
0
def dict_to_menu(parent, menu_dict, menu_widget=None):
    if not menu_widget:
        menu_widget = QMenu(parent)
    for k, v in menu_dict.items():
        if isinstance(v, dict):
            new_menu = menu_widget.addMenu(k)
            dict_to_menu(v, menu_widget=new_menu)
        else:
            act = QAction(k, menu_widget)

            if isinstance(v, list):
                if v[0] == 'checkable':
                    v = v[1]
                    act.setCheckable(True)
                    act.setChecked(False)

            act.triggered.connect(v)
            menu_widget.addAction(act)
    return menu_widget
Exemplo n.º 14
0
    def _dict_to_menu(self, menu_dict):
        '''Stolen shamelessly from specviz. Thanks!'''
        menu_widget = QMenu()
        for k, v in menu_dict.items():
            if isinstance(v, dict):
                new_menu = menu_widget.addMenu(k)
                self._dict_to_menu(v, menu_widget=new_menu)
            else:
                act = QAction(k, menu_widget)

                if isinstance(v, list):
                    if v[0] == 'checkable':
                        v = v[1]
                        act.setCheckable(True)
                        act.setChecked(True)

                act.triggered.connect(v)
                menu_widget.addAction(act)
        return menu_widget
Exemplo n.º 15
0
    def _make_sort_button(self):
        """
        Make the sort button, with separate groups for ascending and
        descending, sorting by name or last shown
        :return: The sort menu button
        """
        sort_button = QPushButton("Sort")
        sort_menu = QMenu()

        ascending_action = QAction("Ascending", sort_menu, checkable=True)
        ascending_action.setChecked(True)
        ascending_action.toggled.connect(self.presenter.set_sort_order)
        descending_action = QAction("Descending", sort_menu, checkable=True)

        order_group = QActionGroup(sort_menu)
        order_group.addAction(ascending_action)
        order_group.addAction(descending_action)

        number_action = QAction("Number", sort_menu, checkable=True)
        number_action.setChecked(True)
        number_action.toggled.connect(
            lambda: self.presenter.set_sort_type(Column.Number))
        name_action = QAction("Name", sort_menu, checkable=True)
        name_action.toggled.connect(
            lambda: self.presenter.set_sort_type(Column.Name))
        last_active_action = QAction("Last Active", sort_menu, checkable=True)
        last_active_action.toggled.connect(
            lambda: self.presenter.set_sort_type(Column.LastActive))

        sort_type_group = QActionGroup(sort_menu)
        sort_type_group.addAction(number_action)
        sort_type_group.addAction(name_action)
        sort_type_group.addAction(last_active_action)

        sort_menu.addAction(ascending_action)
        sort_menu.addAction(descending_action)
        sort_menu.addSeparator()
        sort_menu.addAction(number_action)
        sort_menu.addAction(name_action)
        sort_menu.addAction(last_active_action)

        sort_button.setMenu(sort_menu)
        return sort_button
Exemplo n.º 16
0
class MainWindowMenu(QMenu):
    def __init__(self, parent):
        super(MainWindowMenu, self).__init__(parent)
        self.setTitle("QtPyBotnet")

        self.console_action = QAction('Show console', self)
        self.console_action.setObjectName("show_console")
        self.addAction(self.console_action)

        self.stay_top_action = QAction("Stay on top", self)
        self.stay_top_action.setObjectName("stay_top_action")
        self.stay_top_action.setCheckable(True)
        self.stay_top_action.setChecked(
            bool(self.window().windowFlags() & Qt.WindowStaysOnTopHint))
        self.addAction(self.stay_top_action)

        self.style_picker_action = QWidgetAction(self)
        self.style_picker = StylePickerHorizontal(self)
        self.style_picker_action.setDefaultWidget(self.style_picker)
        self.addAction(self.style_picker_action)
Exemplo n.º 17
0
    def _dict_to_menu(self, menu_dict,  menu_widget=None):
        '''Stolen shamelessly from specviz. Thanks!'''
        if not menu_widget:
            menu_widget = QMenu()
        for k, v in menu_dict.items():
            if isinstance(v, dict):
                new_menu = menu_widget.addMenu(k)
                self._dict_to_menu(v, menu_widget=new_menu)
            else:
                act = QAction(k, menu_widget)

                if isinstance(v, list):
                    if v[0] == 'checkable':
                        v = v[1]
                        act.setCheckable(True)
                        act.setChecked(False)

                act.triggered.connect(v)
                menu_widget.addAction(act)
        return menu_widget
Exemplo n.º 18
0
    def _action(self,
                title,
                icon,
                shortcut,
                target,
                checkable=False,
                checked=False):

        action = QAction(title, self)
        if icon:
            action.setIcon(self._ide.theme.qicon(icon))
        if shortcut:
            action.setShortcut(shortcut)
            action.setToolTip(u'{} ({})'.format(title.replace(u'&', u''),
                                                shortcut))
        action.triggered.connect(target)
        if checkable:
            action.setCheckable(True)
            action.setChecked(checked)
        action.setPriority(QAction.HighPriority)
        return action
Exemplo n.º 19
0
    def _make_sort_button(self):
        """
        Make the sort button, with separate groups for ascending and
        descending, sorting by name or last shown
        :return: The sort menu button
        """
        sort_button = QPushButton("Sort")
        sort_menu = QMenu()

        ascending_action = QAction("Ascending", sort_menu, checkable=True)
        ascending_action.setChecked(True)
        ascending_action.toggled.connect(self.presenter.set_sort_order)
        descending_action = QAction("Descending", sort_menu, checkable=True)

        order_group = QActionGroup(sort_menu)
        order_group.addAction(ascending_action)
        order_group.addAction(descending_action)

        number_action = QAction("Number", sort_menu, checkable=True)
        number_action.setChecked(True)
        number_action.toggled.connect(lambda: self.presenter.set_sort_type(Column.Number))
        name_action = QAction("Name", sort_menu, checkable=True)
        name_action.toggled.connect(lambda: self.presenter.set_sort_type(Column.Name))
        last_active_action = QAction("Last Active", sort_menu, checkable=True)
        last_active_action.toggled.connect(lambda: self.presenter.set_sort_type(Column.LastActive))

        sort_type_group = QActionGroup(sort_menu)
        sort_type_group.addAction(number_action)
        sort_type_group.addAction(name_action)
        sort_type_group.addAction(last_active_action)

        sort_menu.addAction(ascending_action)
        sort_menu.addAction(descending_action)
        sort_menu.addSeparator()
        sort_menu.addAction(number_action)
        sort_menu.addAction(name_action)
        sort_menu.addAction(last_active_action)

        sort_button.setMenu(sort_menu)
        return sort_button
Exemplo n.º 20
0
    def menu_actions(self):
        """
        List of QtWidgets.QActions to be attached to this tool
        as a context menu.
        """
        self.options = []

        # WARNING: QAction labels are used to identify them.
        #          Changing them can cause problems unless
        #          all references are updated in this package.
        component_action_group = QActionGroup(self.tool_bar)

        action = QAction("Off", self.tool_bar, checkable=True)
        action.setChecked(True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.remove_contour)
        self.options.append(action)

        action = QAction("Current Component", self.tool_bar, checkable=True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.default_contour)
        self.options.append(action)

        action = QAction("Other Component", self.tool_bar, checkable=True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.custom_contour)
        self.options.append(action)

        action = QAction(" ", self.tool_bar)
        action.setSeparator(True)
        self.options.append(action)

        action = QAction("Contour Settings", self.tool_bar)
        action.triggered.connect(self.viewer.edit_contour_settings)
        self.options.append(action)

        return self.options
Exemplo n.º 21
0
    def menu_actions(self):
        """
        List of QtWidgets.QActions to be attached to this tool
        as a context menu.
        """
        self.options = []

        # WARNING: QAction labels are used to identify them.
        #          Changing them can cause problems unless
        #          all references are updated in this package.
        component_action_group = QActionGroup(self.tool_bar)

        action = QAction("Off", self.tool_bar, checkable=True)
        action.setChecked(True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.remove_contour)
        self.options.append(action)

        action = QAction("Current Component", self.tool_bar, checkable=True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.default_contour)
        self.options.append(action)

        action = QAction("Other Component", self.tool_bar, checkable=True)
        action.setActionGroup(component_action_group)
        action.triggered.connect(self.viewer.custom_contour)
        self.options.append(action)

        action = QAction(" ", self.tool_bar)
        action.setSeparator(True)
        self.options.append(action)

        action = QAction("Contour Settings", self.tool_bar)
        action.triggered.connect(self.viewer.edit_contour_settings)
        self.options.append(action)

        return self.options
Exemplo n.º 22
0
    def initactions(self):
        self.clear()

        self.actions = []

        for category in self.categories:
            if not category in self.panels.keys(): continue
            panels = self.panels[category]
            keys = sorted(panels.keys())
            for panid in keys:
                if category == self.parent().category and panid == self.parent(
                ).panid:
                    continue
                panel = panels[panid]
                action = QAction(panel.windowTitle())
                action.setCheckable(True)
                action.setChecked((category,
                                   panel.panid) in self.panel.bindings)
                action.triggered.connect(
                    FuncToPanel(self.func, category, panel.panid))
                self.addAction(action)
                self.actions.append(action)

            self.addSeparator()
Exemplo n.º 23
0
 def _create_action(self,
                    text,
                    slot=None,
                    shortcut=None,
                    icon=None,
                    tip=None,
                    checkable=False,
                    checked=False):
     """Convenience function to create actions"""
     action = QAction(text, self)
     if icon is not None:
         action.setIcon(QIcon(icon))
     if shortcut is not None:
         action.setShortcut(shortcut)
     if tip is not None:
         action.setToolTip(tip)
         action.setStatusTip(tip)
     if slot is not None:
         action.triggered.connect(slot)
     if checkable:
         action.setCheckable(True)
         if checked:
             action.setChecked(True)
     return action
Exemplo n.º 24
0
    def generateContextMenu(self):
        """
        Generate the window's context menu. This first calls the base class's
        context menu generator and then extends it with the filtering options.
        """
        qmenu = super(MessageDisplay, self).generateContextMenu()
        filter_menu = qmenu.addMenu("&View")

        framework_action = QAction('Mantid Log Output', filter_menu)
        framework_action.triggered.connect(self.toggle_filter_framework_output)
        framework_action.setCheckable(True)
        framework_action.setChecked(self.showFrameworkOutput())
        filter_menu.addAction(framework_action)

        filter_menu.addSeparator()

        actions_to_group = []
        active_script_action = QAction("Active Tab Output", filter_menu)
        active_script_action.triggered.connect(self.show_active_script)
        actions_to_group.append(active_script_action)
        all_script_action = QAction('All Script Output', filter_menu)
        all_script_action.triggered.connect(self.show_all_scripts)
        actions_to_group.append(all_script_action)
        hide_all_script_action = QAction("Hide All Script Output", filter_menu)
        hide_all_script_action.triggered.connect(self.hide_all_scripts)
        actions_to_group.append(hide_all_script_action)

        action_group = QActionGroup(filter_menu)
        for action in actions_to_group:
            action_group.addAction(action)
            filter_menu.addAction(action)
            action.setCheckable(True)

        if self.showAllScriptOutput():
            all_script_action.setChecked(True)
        elif self.showActiveScriptOutput():
            active_script_action.setChecked(True)
        else:
            hide_all_script_action.setChecked(True)
        return qmenu
Exemplo n.º 25
0
    def _popup_menu(self, event):
        axes = self._find_calling_axes(event)  # find axes calling right click
        if axes is None: return

        pos = self.parent.mapFromGlobal(QtGui.QCursor().pos())

        popup_menu = QMenu(self.parent)
        xScaleMenu = popup_menu.addMenu('x-scale')
        yScaleMenu = popup_menu.addMenu('y-scale')

        for coord in ['x', 'y']:
            menu = eval(coord + 'ScaleMenu')
            for type in axes.scale[coord].keys():
                action = QAction(type, menu, checkable=True)
                if axes.scale[coord][type]:  # if it's checked
                    action.setEnabled(False)
                else:
                    action.setEnabled(True)
                menu.addAction(action)
                action.setChecked(axes.scale[coord][type])
                fcn = lambda event, coord=coord, type=type: self._set_scale(
                    coord, type, axes, True)
                action.triggered.connect(fcn)

        # Create menu for AutoScale options X Y All
        popup_menu.addSeparator()
        autoscale_options = ['AutoScale X', 'AutoScale Y', 'AutoScale All']
        for n, text in enumerate(autoscale_options):
            action = QAction(text, menu, checkable=True)
            if n < len(self.autoScale):
                action.setChecked(self.autoScale[n])
            else:
                action.setChecked(all(self.autoScale))
            popup_menu.addAction(action)
            action.toggled.connect(
                lambda event, n=n: self._setAutoScale(n, event, axes))

        popup_menu.exec_(self.parent.mapToGlobal(pos))
Exemplo n.º 26
0
class ObjectExplorer(BaseDialog, SpyderConfigurationAccessor):
    """Object explorer main widget window."""
    CONF_SECTION = 'variable_explorer'

    def __init__(self,
                 obj,
                 name='',
                 expanded=False,
                 resize_to_contents=True,
                 parent=None,
                 attribute_columns=DEFAULT_ATTR_COLS,
                 attribute_details=DEFAULT_ATTR_DETAILS,
                 readonly=None,
                 reset=False):
        """
        Constructor

        :param name: name of the object as it will appear in the root node
        :param expanded: show the first visible root element expanded
        :param resize_to_contents: resize columns to contents ignoring width
            of the attributes
        :param obj: any Python object or variable
        :param attribute_columns: list of AttributeColumn objects that
            define which columns are present in the table and their defaults
        :param attribute_details: list of AttributeDetails objects that define
            which attributes can be selected in the details pane.
        :param reset: If true the persistent settings, such as column widths,
            are reset.
        """
        QDialog.__init__(self, parent=parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        # Options
        show_callable_attributes = self.get_conf('show_callable_attributes')
        show_special_attributes = self.get_conf('show_special_attributes')

        # Model
        self._attr_cols = attribute_columns
        self._attr_details = attribute_details
        self.readonly = readonly

        self.btn_save_and_close = None
        self.btn_close = None

        self._tree_model = TreeModel(obj,
                                     obj_name=name,
                                     attr_cols=self._attr_cols)

        self._proxy_tree_model = TreeProxyModel(
            show_callable_attributes=show_callable_attributes,
            show_special_attributes=show_special_attributes)

        self._proxy_tree_model.setSourceModel(self._tree_model)
        # self._proxy_tree_model.setSortRole(RegistryTableModel.SORT_ROLE)
        self._proxy_tree_model.setDynamicSortFilter(True)
        # self._proxy_tree_model.setSortCaseSensitivity(Qt.CaseInsensitive)

        # Tree widget
        self.obj_tree = ToggleColumnTreeView()
        self.obj_tree.setAlternatingRowColors(True)
        self.obj_tree.setModel(self._proxy_tree_model)
        self.obj_tree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.obj_tree.setUniformRowHeights(True)
        self.obj_tree.add_header_context_menu()

        # Views
        self._setup_actions()
        self._setup_menu(show_callable_attributes=show_callable_attributes,
                         show_special_attributes=show_special_attributes)
        self._setup_views()
        if name:
            name = "{} -".format(name)
        self.setWindowTitle("{} {}".format(name, EDITOR_NAME))
        self.setWindowFlags(Qt.Window)

        self._resize_to_contents = resize_to_contents
        self._readViewSettings(reset=reset)

        # Update views with model
        self.toggle_show_special_attribute_action.setChecked(
            show_special_attributes)
        self.toggle_show_callable_action.setChecked(show_callable_attributes)

        # Select first row so that a hidden root node will not be selected.
        first_row_index = self._proxy_tree_model.firstItemIndex()
        self.obj_tree.setCurrentIndex(first_row_index)
        if self._tree_model.inspectedNodeIsVisible or expanded:
            self.obj_tree.expand(first_row_index)

    def get_value(self):
        """Get editor current object state."""
        return self._tree_model.inspectedItem.obj

    def _make_show_column_function(self, column_idx):
        """Creates a function that shows or hides a column."""
        show_column = lambda checked: self.obj_tree.setColumnHidden(
            column_idx, not checked)
        return show_column

    def _setup_actions(self):
        """Creates the main window actions."""
        # Show/hide callable objects
        self.toggle_show_callable_action = QAction(
            _("Show callable attributes"),
            self,
            checkable=True,
            shortcut=QKeySequence("Alt+C"),
            statusTip=_("Shows/hides attributes that are callable "
                        "(functions, methods, etc)"))
        self.toggle_show_callable_action.toggled.connect(
            self._proxy_tree_model.setShowCallables)
        self.toggle_show_callable_action.toggled.connect(
            self.obj_tree.resize_columns_to_contents)

        # Show/hide special attributes
        self.toggle_show_special_attribute_action = QAction(
            _("Show __special__ attributes"),
            self,
            checkable=True,
            shortcut=QKeySequence("Alt+S"),
            statusTip=_("Shows or hides __special__ attributes"))
        self.toggle_show_special_attribute_action.toggled.connect(
            self._proxy_tree_model.setShowSpecialAttributes)
        self.toggle_show_special_attribute_action.toggled.connect(
            self.obj_tree.resize_columns_to_contents)

    def _setup_menu(self,
                    show_callable_attributes=False,
                    show_special_attributes=False):
        """Sets up the main menu."""
        self.tools_layout = QHBoxLayout()

        callable_attributes = create_toolbutton(
            self,
            text=_("Show callable attributes"),
            icon=ima.icon("class"),
            toggled=self._toggle_show_callable_attributes_action)
        callable_attributes.setCheckable(True)
        callable_attributes.setChecked(show_callable_attributes)
        self.tools_layout.addWidget(callable_attributes)

        special_attributes = create_toolbutton(
            self,
            text=_("Show __special__ attributes"),
            icon=ima.icon("private2"),
            toggled=self._toggle_show_special_attributes_action)
        special_attributes.setCheckable(True)
        special_attributes.setChecked(show_special_attributes)
        self.tools_layout.addWidget(special_attributes)

        self.tools_layout.addStretch()

        self.options_button = create_toolbutton(self,
                                                text=_('Options'),
                                                icon=ima.icon('tooloptions'))
        self.options_button.setPopupMode(QToolButton.InstantPopup)

        self.show_cols_submenu = QMenu(self)
        self.options_button.setMenu(self.show_cols_submenu)
        # Don't show menu arrow and remove padding
        if is_dark_interface():
            self.options_button.setStyleSheet(
                ("QToolButton::menu-indicator{image: none;}\n"
                 "QToolButton{padding: 3px;}"))
        else:
            self.options_button.setStyleSheet(
                "QToolButton::menu-indicator{image: none;}")
        self.tools_layout.addWidget(self.options_button)

    @Slot()
    def _toggle_show_callable_attributes_action(self):
        """Toggle show callable atributes action."""
        action_checked = not self.toggle_show_callable_action.isChecked()
        self.toggle_show_callable_action.setChecked(action_checked)
        self.set_conf('show_callable_attributes', action_checked)

    @Slot()
    def _toggle_show_special_attributes_action(self):
        """Toggle show special attributes action."""
        action_checked = (
            not self.toggle_show_special_attribute_action.isChecked())
        self.toggle_show_special_attribute_action.setChecked(action_checked)
        self.set_conf('show_special_attributes', action_checked)

    def _setup_views(self):
        """Creates the UI widgets."""
        self.central_splitter = QSplitter(self, orientation=Qt.Vertical)
        layout = create_plugin_layout(self.tools_layout, self.central_splitter)
        self.setLayout(layout)

        # Stretch last column?
        # It doesn't play nice when columns are hidden and then shown again.
        obj_tree_header = self.obj_tree.header()
        obj_tree_header.setSectionsMovable(True)
        obj_tree_header.setStretchLastSection(False)
        add_actions(self.show_cols_submenu,
                    self.obj_tree.toggle_column_actions_group.actions())

        self.central_splitter.addWidget(self.obj_tree)

        # Bottom pane
        bottom_pane_widget = QWidget()
        bottom_layout = QHBoxLayout()
        bottom_layout.setSpacing(0)
        bottom_layout.setContentsMargins(5, 5, 5, 5)  # left top right bottom
        bottom_pane_widget.setLayout(bottom_layout)
        self.central_splitter.addWidget(bottom_pane_widget)

        group_box = QGroupBox(_("Details"))
        bottom_layout.addWidget(group_box)

        v_group_layout = QVBoxLayout()
        h_group_layout = QHBoxLayout()
        h_group_layout.setContentsMargins(2, 2, 2, 2)  # left top right bottom
        group_box.setLayout(v_group_layout)
        v_group_layout.addLayout(h_group_layout)

        # Radio buttons
        radio_widget = QWidget()
        radio_layout = QVBoxLayout()
        radio_layout.setContentsMargins(0, 0, 0, 0)  # left top right bottom
        radio_widget.setLayout(radio_layout)

        self.button_group = QButtonGroup(self)
        for button_id, attr_detail in enumerate(self._attr_details):
            radio_button = QRadioButton(attr_detail.name)
            radio_layout.addWidget(radio_button)
            self.button_group.addButton(radio_button, button_id)

        self.button_group.buttonClicked[int].connect(
            self._change_details_field)
        self.button_group.button(0).setChecked(True)

        radio_layout.addStretch(1)
        h_group_layout.addWidget(radio_widget)

        # Editor widget
        self.editor = SimpleCodeEditor(self)
        self.editor.setReadOnly(True)
        h_group_layout.addWidget(self.editor)

        # Save and close buttons
        btn_layout = QHBoxLayout()
        btn_layout.addStretch()

        if not self.readonly:
            self.btn_save_and_close = QPushButton(_('Save and Close'))
            self.btn_save_and_close.setDisabled(True)
            self.btn_save_and_close.clicked.connect(self.accept)
            btn_layout.addWidget(self.btn_save_and_close)

        self.btn_close = QPushButton(_('Close'))
        self.btn_close.setAutoDefault(True)
        self.btn_close.setDefault(True)
        self.btn_close.clicked.connect(self.reject)
        btn_layout.addWidget(self.btn_close)
        v_group_layout.addLayout(btn_layout)

        # Splitter parameters
        self.central_splitter.setCollapsible(0, False)
        self.central_splitter.setCollapsible(1, True)
        self.central_splitter.setSizes([500, 320])

        # Connect signals
        # Keep a temporary reference of the selection_model to prevent
        # segfault in PySide.
        # See http://permalink.gmane.org/gmane.comp.lib.qt.pyside.devel/222
        selection_model = self.obj_tree.selectionModel()
        selection_model.currentChanged.connect(self._update_details)

        # Check if the values of the model have been changed
        self._proxy_tree_model.sig_setting_data.connect(
            self.save_and_close_enable)

        self._proxy_tree_model.sig_update_details.connect(
            self._update_details_for_item)

    # End of setup_methods
    def _readViewSettings(self, reset=False):
        """
        Reads the persistent program settings.

        :param reset: If True, the program resets to its default settings.
        """
        pos = QPoint(20, 20)
        window_size = QSize(825, 650)
        details_button_idx = 0

        header = self.obj_tree.header()
        header_restored = False

        if reset:
            logger.debug("Resetting persistent view settings")
        else:
            pos = pos
            window_size = window_size
            details_button_idx = details_button_idx
            #            splitter_state = settings.value("central_splitter/state")
            splitter_state = None
            if splitter_state:
                self.central_splitter.restoreState(splitter_state)
#            header_restored = self.obj_tree.read_view_settings(
#                'table/header_state',
#                settings, reset)
            header_restored = False

        if not header_restored:
            column_sizes = [col.width for col in self._attr_cols]
            column_visible = [col.col_visible for col in self._attr_cols]

            for idx, size in enumerate(column_sizes):
                if not self._resize_to_contents and size > 0:  # Just in case
                    header.resizeSection(idx, size)
                else:
                    header.resizeSections(QHeaderView.ResizeToContents)
                    break

            for idx, visible in enumerate(column_visible):
                elem = self.obj_tree.toggle_column_actions_group.actions()[idx]
                elem.setChecked(visible)

        self.resize(window_size)

        button = self.button_group.button(details_button_idx)
        if button is not None:
            button.setChecked(True)

    @Slot()
    def save_and_close_enable(self):
        """Handle the data change event to enable the save and close button."""
        if self.btn_save_and_close:
            self.btn_save_and_close.setEnabled(True)
            self.btn_save_and_close.setAutoDefault(True)
            self.btn_save_and_close.setDefault(True)

    @Slot(QModelIndex, QModelIndex)
    def _update_details(self, current_index, _previous_index):
        """Shows the object details in the editor given an index."""
        tree_item = self._proxy_tree_model.treeItem(current_index)
        self._update_details_for_item(tree_item)

    def _change_details_field(self, _button_id=None):
        """Changes the field that is displayed in the details pane."""
        # logger.debug("_change_details_field: {}".format(_button_id))
        current_index = self.obj_tree.selectionModel().currentIndex()
        tree_item = self._proxy_tree_model.treeItem(current_index)
        self._update_details_for_item(tree_item)

    @Slot(TreeItem)
    def _update_details_for_item(self, tree_item):
        """Shows the object details in the editor given an tree_item."""
        try:
            # obj = tree_item.obj
            button_id = self.button_group.checkedId()
            assert button_id >= 0, ("No radio button selected. "
                                    "Please report this bug.")
            attr_details = self._attr_details[button_id]
            data = attr_details.data_fn(tree_item)
            self.editor.setPlainText(data)
            self.editor.setWordWrapMode(attr_details.line_wrap)
            self.editor.setup_editor(
                font=get_font(font_size_delta=DEFAULT_SMALL_DELTA),
                show_blanks=False,
                color_scheme=CONF.get('appearance', 'selected'),
                scroll_past_end=False,
            )
            self.editor.set_text(data)

            if attr_details.name == 'Source code':
                self.editor.set_language('Python')
            else:
                self.editor.set_language('Rst')

        except Exception as ex:
            self.editor.setStyleSheet("color: red;")
            stack_trace = traceback.format_exc()
            self.editor.setPlainText("{}\n\n{}".format(ex, stack_trace))
            self.editor.setWordWrapMode(
                QTextOption.WrapAtWordBoundaryOrAnywhere)

    @classmethod
    def create_explorer(cls, *args, **kwargs):
        """
        Creates and shows and ObjectExplorer window.

        The *args and **kwargs will be passed to the ObjectExplorer constructor

        A (class attribute) reference to the browser window is kept to prevent
        it from being garbage-collected.
        """
        object_explorer = cls(*args, **kwargs)
        object_explorer.exec_()
        return object_explorer
Exemplo n.º 27
0
class MainWindow(QMainWindow):

    def __init__(self, config, window_theme: WindowTheme):
        super(MainWindow, self).__init__()

        self.session = None
        self.theme = window_theme
        self.node_packages = {}  # {Node: str}
        self.script_UIs = []

        # SESSION
        self.session = rc.Session(node_class=NodeBase)

        self.session.flow_view_created.connect(self.script_created)
        self.session.script_renamed.connect(self.script_renamed)
        self.session.script_deleted.connect(self.script_deleted)

        # LOAD DESIGN AND FLOW THEME
        self.session.design.load_from_config('design_config.json')

        if self.theme.name == 'dark':
            self.session.design.set_flow_theme(name='pure dark')
        else:  # 'light'
            self.session.design.set_flow_theme(name='pure light')

        # UI
        self.setup_ui()

        self.flow_view_theme_actions = []
        self.setup_menu_actions()

        self.setWindowTitle('Ryven')
        self.setWindowIcon(QIcon('../resources/pics/Ryven_icon.png'))
        self.ui.scripts_tab_widget.removeTab(0)  # remove placeholder tab

        # SHORTCUTS
        save_shortcut = QShortcut(QKeySequence.Save, self)
        save_shortcut.activated.connect(self.on_save_project_triggered)
        import_nodes_shortcut = QShortcut(QKeySequence('Ctrl+i'), self)
        import_nodes_shortcut.activated.connect(self.on_import_nodes_triggered)

        # TEMP FOLDER
        if not os.path.exists('../temp'):
            os.mkdir('../temp')
        for f in os.listdir('../temp'):
            os.remove('temp/'+f)

        # PROJECT SETUP
        if 'info_msgs' in sys.argv:
            rc.InfoMsgs.enable()

        #   SETUP MAIN CONSOLE
        MainConsole.instance.session = self.session
        MainConsole.instance.reset_interpreter()
        NodeBase.main_console = MainConsole.instance

        #   REGISTER BUILT-IN NODES
        self.import_nodes(path=join(dirname(__file__), 'nodes/built_in/'))

        #   LOAD PROJECT
        if config['config'] == 'create plain new project':
            self.session.create_script(title='hello world')
        elif config['config'] == 'open project':
            print('importing packages...')
            self.import_packages(config['required packages'])
            print('loading project...')
            self.session.load(config['content'])
            print('finished')

        self.resize(1500, 800)
        # self.showMaximized()

    def print_info(self):
        print('''
CONTROLS
place: right mouse
select: left mouse
pan: right mouse
save: ctrl+s
import: ctrl+i
        ''')

    # UI

    def setup_ui(self):
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.statusBar.hide()

        # # nodes tree
        # self.nodes_tree_widget = NodesTreeListWidget(self, self.session)
        # self.ui.bottom_splitter.addWidget(self.nodes_tree_widget)

        # # node details widget
        # self.node_details_widget = NodeDetailsWidget(self, self.nodes_tree_widget)
        # self.ui.bottom_splitter.addWidget(self.node_details_widget)

        # main console
        if MainConsole.instance is not None:
            self.ui.bottom_splitter.addWidget(MainConsole.instance)
        # self.ui.right_vertical_splitter.setSizes([600, 0])

        # splitter sizes
        # self.ui.left_vertical_splitter.setSizes([350, 350])
        self.ui.main_vertical_splitter.setSizes([700, 0])

        self.scripts_list_widget = rc.GUI.ScriptsList(self.session)
        self.scripts_list_widget.create_script_button.setProperty('class', 'small_button')
        self.scripts_list_widget.create_macro_button.setProperty('class', 'small_button')
        self.ui.scripts_groupBox.layout().addWidget(self.scripts_list_widget)

    def setup_menu_actions(self):

        # flow designs
        light_themes_menu = QMenu('light')
        for d in self.session.design.flow_themes:
            design_action = QAction(d.name, self)
            if d.type_ == 'dark':
                self.ui.menuFlow_Design_Style.addAction(design_action)
            else:
                light_themes_menu.addAction(design_action)

            design_action.triggered.connect(self.on_design_action_triggered)
            self.flow_view_theme_actions.append(design_action)

        self.ui.menuFlow_Design_Style.addMenu(light_themes_menu)

        self.ui.actionImport_Nodes.triggered.connect(self.on_import_nodes_triggered)
        self.ui.actionSave_Project.triggered.connect(self.on_save_project_triggered)
        self.ui.actionEnableInfoMessages.triggered.connect(self.on_enable_info_msgs_triggered)
        self.ui.actionDisableInfoMessages.triggered.connect(self.on_disable_info_msgs_triggered)
        self.ui.actionSave_Pic_Viewport.triggered.connect(self.on_save_scene_pic_viewport_triggered)
        self.ui.actionSave_Pic_Whole_Scene_scaled.triggered.connect(self.on_save_scene_pic_whole_triggered)

        # performance mode
        self.ac_perf_mode_fast = QAction('Fast', self)
        self.ac_perf_mode_fast.setCheckable(True)

        self.ac_perf_mode_pretty = QAction('Pretty', self)
        self.ac_perf_mode_pretty.setCheckable(True)

        perf_mode_ag = QActionGroup(self)
        perf_mode_ag.addAction(self.ac_perf_mode_fast)
        perf_mode_ag.addAction(self.ac_perf_mode_pretty)

        self.ac_perf_mode_fast.setChecked(self.session.design.performance_mode == 'fast')
        self.ac_perf_mode_pretty.setChecked(self.session.design.performance_mode == 'pretty')

        perf_mode_ag.triggered.connect(self.on_performance_mode_changed)

        perf_menu = QMenu('Performance Mode', self)
        perf_menu.addAction(self.ac_perf_mode_fast)
        perf_menu.addAction(self.ac_perf_mode_pretty)

        self.ui.menuView.addMenu(perf_menu)

        # animations
        self.ac_anims_active = QAction('Enabled', self)
        self.ac_anims_active.setCheckable(True)

        self.ac_anims_inactive = QAction('Disabled', self)
        self.ac_anims_inactive.setCheckable(True)

        anims_ag = QActionGroup(self)
        anims_ag.addAction(self.ac_anims_active)
        anims_ag.addAction(self.ac_anims_inactive)

        self.ac_anims_active.setChecked(self.session.design.animations_enabled)
        self.ac_anims_inactive.setChecked(not self.session.design.animations_enabled)

        anims_ag.triggered.connect(self.on_animation_enabling_changed)

        animations_menu = QMenu('Animations', self)
        animations_menu.addAction(self.ac_anims_active)
        animations_menu.addAction(self.ac_anims_inactive)

        self.ui.menuView.addMenu(animations_menu)

    def load_stylesheet(self, ss):
        ss_content = ''
        try:
            f = open('../resources/stylesheets/'+ss+'.txt')
            ss_content = f.read()
            f.close()
        finally:
            self.session.set_stylesheet(ss_content)
            self.setStyleSheet(ss_content)

    # SLOTS

    def on_import_nodes_triggered(self):
        file_path = QFileDialog.getOpenFileName(self, 'select nodes file', '../packages', '(*.py)',)[0]
        if file_path != '':
            self.import_nodes(path=dirname(file_path))

    def on_performance_mode_changed(self, action):
        if action == self.ac_perf_mode_fast:
            self.session.design.set_performance_mode('fast')
        else:
            self.session.design.set_performance_mode('pretty')

    def on_animation_enabling_changed(self, action):
        if action == self.ac_anims_active:
            self.session.design.animations_enabled = True
        else:
            self.session.design.animations_enabled = False

    def on_design_action_triggered(self):
        index = self.flow_view_theme_actions.index(self.sender())
        self.session.design.set_flow_theme(self.session.design.flow_themes[index])

    def on_enable_info_msgs_triggered(self):
        rc.InfoMsgs.enable()

    def on_disable_info_msgs_triggered(self):
        rc.InfoMsgs.disable()

    def on_save_scene_pic_viewport_triggered(self):
        """Saves a picture of the currently visible viewport."""
        if len(self.session.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '', 'PNG(*.png)')[0]
        script = self.ui.scripts_tab_widget.currentWidget().script
        view = self.session.flow_views[script]
        img = view.get_viewport_img()
        img.save(file_path)

    def on_save_scene_pic_whole_triggered(self):
        """Saves a picture of the whole currently visible scene."""
        if len(self.session.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '', 'PNG(*.png)')[0]
        script = self.ui.scripts_tab_widget.currentWidget().script
        view = self.session.flow_views[script]
        img = view.get_whole_scene_img()
        img.save(file_path)

    def on_save_project_triggered(self):
        file_name = QFileDialog.getSaveFileName(self, 'select location and give file name',
                                                '../saves', '(*.json)')[0]
        if file_name != '':
            self.save_project(file_name)

    # SESSION

    def script_created(self, script, flow_view):
        script_widget = ScriptUI(self, script, flow_view)
        self.script_UIs.append(script_widget)
        self.ui.scripts_tab_widget.addTab(script_widget, script.title)

    def script_renamed(self, script):
        script_UI, index = self.get_script_ui(script)
        if index != -1:

            self.ui.scripts_tab_widget.setTabText(
                index,
                script.title
            )

    def script_deleted(self, script):
        script_UI, index = self.get_script_ui(script)
        self.ui.scripts_tab_widget.removeTab(index)
        self.script_UIs.remove(script_UI)

    def get_script_ui(self, script):
        script_UI = None
        index = -1
        for index in range(len(self.script_UIs)):
            sui = self.script_UIs[index]
            if sui.script == script:
                script_UI = sui
                break
        return script_UI, index

    def get_current_script(self):
        return self.session.scripts[self.ui.scripts_tab_widget.currentIndex()]

    def import_packages(self, packages_list: [NodesPackage]):
        for p in packages_list:
            self.import_nodes(p)

    def import_nodes(self, package: NodesPackage = None, path: str = None):

        if package is not None:
            p = package
        else:
            p = NodesPackage(path)

        try:
            nodes = import_nodes_package(p)
        except ModuleNotFoundError as e:
            QMessageBox.warning(self, title='Missing Python module', text=str(e))
            sys.exit()

        self.session.register_nodes(nodes)

        for n in nodes:
            self.node_packages[n] = p

        # self.nodes_tree_widget.update_list()

    def save_project(self, file_name):
        import json

        file = None
        try:
            if os.path.exists(file_name):
                os.remove(file_name)
            file = open(file_name, 'w')
        except FileNotFoundError:
            rc.InfoMsgs.write('couldn\'t open file')
            return

        general_project_info_dict = {'type': 'Ryven project file'}

        scripts_data = self.session.serialize()

        required_packages = set()
        for node in self.session.all_node_objects():
            if node.__class__ not in self.node_packages.keys() or \
                    self.node_packages[node.__class__] is None or \
                    self.node_packages[node.__class__].name == 'built_in':
                continue
            required_packages.add(
                self.node_packages[node.__class__]
            )

        whole_project_dict = {'general info': general_project_info_dict,
                              'required packages': [p.config_data() for p in required_packages],
                              **scripts_data}

        data = json.dumps(whole_project_dict, indent=4)
        rc.InfoMsgs.write(data)

        file.write(data)
        file.close()
Exemplo n.º 28
0
class Viewer(ConfigurableMoveableTabContainer):
    """
    Contains multiple TabbedViewingAreas
    """
    tab_titles = Signal([tuple])
    num_viewing_areas = Integer(2, config=True)

    def __init__(self, *args, menuBar, **kwargs):
        super().__init__(*args, **kwargs)
        self._run_to_tabs = collections.defaultdict(list)
        self._title_to_tab = {}
        self._tabs_from_streaming = []
        self._overplot = OverPlotState.individual_tab
        self._overplot_target = None
        self._live_enabled = False

        self._live_run_router = RunRouter([self.route_live_stream])

        self._containers = [
            TabbedViewingArea(viewer=self, menuBar=menuBar)
            for _ in range(self.num_viewing_areas)
        ]
        layout = QVBoxLayout()
        splitter = QSplitter(Qt.Vertical)
        layout.addWidget(splitter)
        for container in self._containers:
            splitter.addWidget(container)
        self.setLayout(layout)

        overplot_group = QActionGroup(self)
        self.off = QAction('&Off', self)
        self.off.setStatusTip('Drop streaming data.')
        self.individual_tab = QAction('&New Tab', self)
        self.individual_tab.setStatusTip('Open a new viewer tab for each Run.')
        self.latest_live = QAction('&Latest Live Tab', self)
        self.latest_live.setStatusTip(
            'Attempt to overplot on the most recent live Run.')
        self.fixed = QAction('&Fixed Tab...', self)
        self.fixed.setStatusTip('Attempt to overplot on a specific tab.')
        self.fixed.setEnabled(False)
        overplot_group.addAction(self.off)
        overplot_group.addAction(self.individual_tab)
        overplot_group.addAction(self.latest_live)
        overplot_group.addAction(self.fixed)
        for action in overplot_group.actions():
            action.setCheckable(True)
        overplot_group.setExclusive(True)
        self.off.setChecked(True)

        overplot_menu = menuBar().addMenu('&Streaming')
        overplot_menu.addActions(overplot_group.actions())

        self.off.triggered.connect(self.disable_live)
        self.individual_tab.triggered.connect(
            partial(self.set_overplot_state, OverPlotState.individual_tab))
        self.latest_live.triggered.connect(
            partial(self.set_overplot_state, OverPlotState.latest_live))

        def set_overplot_target():
            item, ok = QInputDialog.getItem(self, "Select Tab", "Tab",
                                            tuple(self._title_to_tab), 0,
                                            False)
            if not ok:
                # Abort and fallback to Off. Would be better to fall back to
                # previous state (which could be latest_live) but it's not
                # clear how to know what that state was.
                self.off.setChecked(True)
                return
            self.set_overplot_state(OverPlotState.fixed)
            self._overplot_target = item

        self.fixed.triggered.connect(set_overplot_target)

    def enable_live(self):
        self._live_enabled = True

    def disable_live(self):
        self._live_enabled = False

    def consumer(self, item):
        """Slot that receives (name, doc) and unpacks it into RunRouter."""
        self._live_run_router(*item)

    def route_live_stream(self, name, start_doc):
        """Create or choose a Viewer to receive this Run."""
        if not self._live_enabled:
            log.debug("Streaming Run ignored because Streaming is disabled.")
            return [], []
        self.fixed.setEnabled(True)
        target_area = self._containers[0]
        uid = start_doc['uid']
        if self._overplot == OverPlotState.individual_tab:
            viewer = RunViewer()
            tab_title = uid[:8]
            index = target_area.addTab(viewer, tab_title)
            self._title_to_tab[tab_title] = viewer
            self._tabs_from_streaming.append(viewer)
            target_area.setCurrentIndex(index)
            self.tab_titles.emit(tuple(self._title_to_tab))
        elif self._overplot == OverPlotState.fixed:
            viewer = self._title_to_tab[self._overplot_target]
        elif self._overplot == OverPlotState.latest_live:
            if self._tabs_from_streaming:
                viewer = self._tabs_from_streaming[-1]
            else:
                viewer = RunViewer()
                tab_title = uid[:8]
                index = target_area.addTab(viewer, tab_title)
                self._title_to_tab[tab_title] = viewer
                self._tabs_from_streaming.append(viewer)
                target_area.setCurrentIndex(index)
                self.tab_titles.emit(tuple(self._title_to_tab))
        self._run_to_tabs[uid].append(viewer)
        viewer.run_router('start', start_doc)

        return [viewer.run_router], []

    def show_entries(self, target, entries):
        self.fixed.setEnabled(True)
        target_area = self._containers[0]
        if not target:
            # Add new Viewer tab.
            viewer = RunViewer()
            if len(entries) == 1:
                entry, = entries
                uid = entry.describe()['metadata']['start']['uid']
                tab_title = uid[:8]
            else:
                tab_title = self.get_title()
            index = target_area.addTab(viewer, tab_title)
            self._title_to_tab[tab_title] = viewer
            target_area.setCurrentIndex(index)
            self.tab_titles.emit(tuple(self._title_to_tab))
        else:
            viewer = self._title_to_tab[target]
        for entry in entries:
            viewer.load_entry(entry)
            uid = entry.describe()['metadata']['start']['uid']
            self._run_to_tabs[uid].append(viewer)
        # TODO Make last entry in the list the current widget.

    def get_title(self):
        for i in itertools.count(1):
            title = f'Group {i}'
            if title in self._title_to_tab:
                continue
            return title

    def set_overplot_state(self, state):
        self.enable_live()
        log.debug('Overplot state is %s', state)
        self._overplot = state

    def close_run_viewer(self, widget):
        try:
            self._tabs_from_streaming.remove(widget)
        except ValueError:
            pass
        for uid in widget.uids:
            self._run_to_tabs[uid].remove(widget)
            for title, tab in list(self._title_to_tab.items()):
                if tab == widget:
                    del self._title_to_tab[title]
                    self.tab_titles.emit(tuple(self._title_to_tab))
                    if title == self._overplot_target:
                        self.set_overplot_state(OverPlotState.off)
        if not self._title_to_tab:
            self.fixed.setEnabled(False)
Exemplo n.º 29
0
    def __init__(self, control, path, fgprintindex):
        Q7Window.__init__(self, Q7Window.VIEW_TREE, control, path, fgprintindex)
        self._depthExpanded = 0
        self._lastEntered = None
        self.lastdiag = None
        self._linkwindow = None
        self._querywindow = None
        self._vtkwindow = None
        self._selectwindow = None
        self._column = {NMT.COLUMN_SIDS: OCTXT.ShowSIDSColumn,
                        NMT.COLUMN_FLAG_LINK: OCTXT.ShowLinkColumn,
                        NMT.COLUMN_FLAG_SELECT: OCTXT.ShowSelectColumn,
                        NMT.COLUMN_FLAG_CHECK: OCTXT.ShowCheckColumn,
                        NMT.COLUMN_FLAG_USER: OCTXT.ShowUserColumn,
                        NMT.COLUMN_SHAPE: OCTXT.ShowShapeColumn,
                        NMT.COLUMN_DATATYPE: OCTXT.ShowDataTypeColumn}
        self.selectForLinkSrc = None  # one link source per tree view allowed

        #self.treeview.expanded[QModelIndex].connect(self.expandNode)
        self.treeview.collapsed.connect(self.collapseNode)
        self.treeview.pressed[QModelIndex].connect(self.clickedPressedNode)
        self.treeview.customContextMenuRequested.connect(self.clickedNode)

        # QObject.connect(self.treeview,
        #                SIGNAL("expanded(QModelIndex)"),
        #                self.expandNode)
        # QObject.connect(self.treeview,
        #                SIGNAL("collapsed()"),
        #                self.collapseNode)
        # QObject.connect(self.treeview,
        #                SIGNAL("pressed(QModelIndex)"),
        #                self.clickedPressedNode)
        # QObject.connect(self.treeview,
        #                SIGNAL("customContextMenuRequested(QPoint)"),
        #                self.clickedNode)

        self.bSave.clicked.connect(self.savetree)
        self.lockable(self.bSave)
        self.bQueryView.clicked.connect(self.queryview)
        self.lockable(self.bQueryView)
        self.bSaveAs.clicked.connect(self.savetreeas)
        self.lockable(self.bSaveAs)
        self.bInfo.clicked.connect(self.infoTreeView)
        self.bZoomIn.clicked.connect(self.expandLevel)
        self.bZoomOut.clicked.connect(self.collapseLevel)
        self.bZoomAll.clicked.connect(self.expandMinMax)
        self.bFormView.clicked.connect(self.formview)
        self.bMarkAll.clicked.connect(self.markall)
        self.bUnmarkAll_1.clicked.connect(self.unmarkall)
        self.bUnmarkAll_2.clicked.connect(self.unmarkall)
        self.bPreviousMark.clicked.connect(self.previousmark)
        self.bNextMark.clicked.connect(self.nextmark)
        self.bSwapMarks.clicked.connect(self.swapmarks)
        self.bMarksAsList.clicked.connect(self.selectionlist)
        self.bVTKView.clicked.connect(self.vtkview)
        self.lockable(self.bVTKView)
        self.bScreenShot.clicked.connect(self.screenshot)
        self.bCheck.clicked.connect(self.check)
        self.bCheckList.clicked.connect(self.checklist)
        self.bClearChecks.clicked.connect(self.clearchecks)
        self.bLinkView.clicked.connect(self.linklist)
        self.bPatternView.clicked.connect(self.patternlist)
        self.bToolsView.clicked.connect(self.tools)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.popupmenu = QMenu()
        self.diagview = None
        lmodel = self.FG.model
        self.treeview.setModel(lmodel)
        self.treeview.setItemDelegate(Q7TreeItemDelegate(self.treeview, lmodel))
        self.treeview.setControlWindow(self, self.FG.index)
        if (self._control.transientRecurse or OCTXT.RecursiveTreeDisplay):
            self.expandMinMax()
        if (self._control.transientVTK): self.vtkview()
        self._control.transientRecurse = False
        self._control.transientVTK = False
        self.clearchecks()
        #
        self.bCheckList.setDisabled(True)
        if (not OCTXT._HasProPackage):
            self.bToolsView.setDisabled(True)
        self.bCheckView.setDisabled(True)
        self.bPatternDB.setDisabled(True)
        self.bAddLink.clicked.connect(self.linkadd)
        self.bSelectLinkSrc.clicked.connect(self.linkselectsrc)
        self.bSelectLinkDst.clicked.connect(self.linkselectdst)
        self.bAddLink.setDisabled(True)
        self.lineEdit.returnPressed.connect(self.jumpToNode)
        # QObject.connect(self.lineEdit,
        #                SIGNAL("returnPressed()"),
        #                self.jumpToNode)
        tvh = self.treeview.header()
        tvh.setContextMenuPolicy(Qt.CustomContextMenu)
        tvh.customContextMenuRequested.connect(self.headerMenu)
        self._hmenu = QMenu()
        self._hmenu._idx = {}
        self._tlist = (('SIDS type', NMT.COLUMN_SIDS),
                       ('Link flag', NMT.COLUMN_FLAG_LINK),
                       ('Mark flag', NMT.COLUMN_FLAG_SELECT),
                       ('Check flag', NMT.COLUMN_FLAG_CHECK),
                       ('User flag', NMT.COLUMN_FLAG_USER),
                       ('Shape', NMT.COLUMN_SHAPE),
                       ('Data type', NMT.COLUMN_DATATYPE))
        for (tag, idx) in self._tlist:
            a = QAction(tag, self._hmenu, checkable=True)
            self._hmenu._idx[idx] = a
            if (self._column[idx]):
                a.setChecked(True)
            else:
                a.setChecked(False)
            self._hmenu.addAction(a)
            self.treeview.setColumnHidden(idx, not self._column[idx])
        self._recursiveAddNewNode = False
        self.updateTreeStatus()
Exemplo n.º 30
0
class MainWindow(QMainWindow):

    signal_fitting_parameters_changed = Signal()

    def __init__(self, *, gpc):
        """
        Parameters
        ----------
        gpc: object
            reference to a class that holds references to processing classes.
        """
        super().__init__()

        self._cursor_set = False  # Indicates if temporary 'wait' cursor is set

        self.gpc = gpc
        self.gui_vars = global_gui_variables
        self.gui_vars["ref_main_window"] = self

        self.wnd_manage_emission_lines = WndManageEmissionLines(gpc=self.gpc, gui_vars=self.gui_vars)
        self.wnd_compute_roi_maps = WndComputeRoiMaps(gpc=self.gpc, gui_vars=self.gui_vars)
        self.wnd_image_wizard = WndImageWizard(gpc=self.gpc, gui_vars=self.gui_vars)
        self.wnd_load_quantitative_calibration = WndLoadQuantitativeCalibration(
            gpc=self.gpc, gui_vars=self.gui_vars
        )
        self.wnd_general_fitting_settings = WndGeneralFittingSettings(gpc=self.gpc, gui_vars=self.gui_vars)
        self.wnd_fitting_parameters_shared = WndDetailedFittingParamsShared(gpc=self.gpc, gui_vars=self.gui_vars)
        self.wnd_fitting_parameters_lines = WndDetailedFittingParamsLines(gpc=self.gpc, gui_vars=self.gui_vars)
        # Indicates that the window was closed (used mostly for testing)
        self._is_closed = False

        global_gui_variables["gui_state"]["databroker_available"] = self.gpc.is_databroker_available()

        self.initialize()

        self.central_widget.left_panel.load_data_widget.update_main_window_title.connect(self.update_window_title)

        # Set the callback for update forms with fitting parameters
        def update_fitting_parameter_forms():
            self.signal_fitting_parameters_changed.emit()

        gpc.add_parameters_changed_cb(update_fitting_parameter_forms)
        gpc.param_model.parameters_changed()

    def initialize(self):

        self.resize(_main_window_geometry["initial_width"], _main_window_geometry["initial_height"])

        self.setMinimumWidth(_main_window_geometry["min_width"])
        self.setMinimumHeight(_main_window_geometry["min_height"])

        self.setWindowTitle(self.gpc.get_window_title())

        self.central_widget = TwoPanelWidget(gpc=self.gpc, gui_vars=self.gui_vars)
        self.setCentralWidget(self.central_widget)

        # Status bar
        self.statusLabel = QLabel()
        self.statusBar().addWidget(self.statusLabel)
        self.statusProgressBar = QProgressBar()
        self.statusProgressBar.setFixedWidth(200)
        self.statusBar().addPermanentWidget(self.statusProgressBar)

        self.statusLabelDefaultText = "No data is loaded"
        self.statusLabel.setText(self.statusLabelDefaultText)

        # 'Scan Data' menu item
        self.action_read_file = QAction("&Read File...", self)
        self.action_read_file.setStatusTip("Load data from HDF5 file")
        self.action_read_file.triggered.connect(self.central_widget.left_panel.load_data_widget.pb_file.clicked)

        self.action_load_run = QAction("&Load Run...", self)
        self.action_load_run.setEnabled(self.gui_vars["gui_state"]["databroker_available"])
        self.action_load_run.setStatusTip("Load data from database (Databroker)")
        self.action_load_run.triggered.connect(self.central_widget.left_panel.load_data_widget.pb_dbase.clicked)

        self.action_view_metadata = QAction("View Metadata...", self)
        self.action_view_metadata.setEnabled(self.gpc.is_scan_metadata_available())
        self.action_view_metadata.setStatusTip("View metadata for loaded run")
        self.action_view_metadata.triggered.connect(
            self.central_widget.left_panel.load_data_widget.pb_view_metadata.clicked
        )

        # Main menu
        menubar = self.menuBar()
        # Disable native menu bar (it doesn't work on MacOS 10.15 with PyQt<=5.11)
        #   It may work with later versions of PyQt when they become available.
        menubar.setNativeMenuBar(False)
        loadData = menubar.addMenu("Scan &Data")
        loadData.addAction(self.action_read_file)
        loadData.addAction(self.action_load_run)
        loadData.addSeparator()
        loadData.addAction(self.action_view_metadata)

        # 'Fitting Model' menu item
        self.action_lines_find_automatically = QAction("Find &Automatically...", self)
        self.action_lines_find_automatically.setStatusTip("Automatically find emission lines in total spectrum")
        self.action_lines_find_automatically.triggered.connect(
            self.central_widget.left_panel.model_widget.pb_find_elines.clicked
        )

        self.action_lines_load_from_file = QAction("Load From &File...", self)
        self.action_lines_load_from_file.setStatusTip(
            "Load processing parameters, including selected emission lines, from JSON file"
        )
        self.action_lines_load_from_file.triggered.connect(
            self.central_widget.left_panel.model_widget.pb_load_elines.clicked
        )

        self.action_lines_load_quant_standard = QAction("Load &Quantitative Standards...", self)
        self.action_lines_load_quant_standard.setStatusTip(
            "Load quantitative standard. The emission lines from the standard are automatically selected"
        )
        self.action_lines_load_quant_standard.triggered.connect(
            self.central_widget.left_panel.model_widget.pb_load_qstandard.clicked
        )

        self.action_add_remove_emission_lines = QAction("&Add/Remove Emission Lines...", self)
        self.action_add_remove_emission_lines.setStatusTip("Manually add and remove emission lines")
        self.action_add_remove_emission_lines.triggered.connect(
            self.central_widget.left_panel.model_widget.pb_manage_emission_lines.clicked
        )

        self.action_save_model_params = QAction("&Save Model Parameters...", self)
        self.action_save_model_params.setStatusTip("Save model parameters to JSON file")
        self.action_save_model_params.triggered.connect(
            self.central_widget.left_panel.model_widget.pb_save_elines.clicked
        )

        self.action_add_remove_emission_lines = QAction("Start Model &Fitting", self)
        self.action_add_remove_emission_lines.setStatusTip("Run computations: start fitting for total spectrum")
        self.action_add_remove_emission_lines.triggered.connect(
            self.central_widget.left_panel.model_widget.pb_start_fitting.clicked
        )

        fittingModel = menubar.addMenu("Fitting &Model")
        emissionLines = fittingModel.addMenu("&Emission Lines")
        emissionLines.addAction(self.action_lines_find_automatically)
        emissionLines.addAction(self.action_lines_load_from_file)
        emissionLines.addAction(self.action_lines_load_quant_standard)
        fittingModel.addAction(self.action_add_remove_emission_lines)
        fittingModel.addSeparator()
        fittingModel.addAction(self.action_save_model_params)
        fittingModel.addSeparator()
        fittingModel.addAction(self.action_add_remove_emission_lines)

        # "XRF Maps" menu item
        self.action_start_xrf_map_fitting = QAction("Start XRF Map &Fitting", self)
        self.action_start_xrf_map_fitting.setStatusTip("Run computations: start fitting for XRF maps")
        self.action_start_xrf_map_fitting.triggered.connect(
            self.central_widget.left_panel.fit_maps_widget.pb_start_map_fitting.clicked
        )

        self.action_compute_rois = QAction("Compute &ROIs...", self)
        self.action_compute_rois.setStatusTip("Compute XRF Maps based on spectral ROIs")
        self.action_compute_rois.triggered.connect(
            self.central_widget.left_panel.fit_maps_widget.pb_compute_roi_maps.clicked
        )

        self.action_load_quant_calibration = QAction("&Load Quantitative Calibration...", self)
        self.action_load_quant_calibration.setStatusTip(
            "Load quantitative calibration from JSON file. Calibration is used for scaling of XRF Maps"
        )
        self.action_load_quant_calibration.triggered.connect(
            self.central_widget.left_panel.fit_maps_widget.pb_load_quant_calib.clicked
        )

        self.action_save_quant_calibration = QAction("&Save Quantitative Calibration...", self)
        self.action_save_quant_calibration.setStatusTip(
            "Save Quantitative Calibration based on XRF map of the standard sample"
        )
        self.action_save_quant_calibration.triggered.connect(
            self.central_widget.left_panel.fit_maps_widget.pb_save_q_calibration.clicked
        )

        self.action_export_to_tiff_and_txt = QAction("&Export to TIFF and TXT...", self)
        self.action_export_to_tiff_and_txt.setStatusTip("Export XRF Maps as TIFF and/or TXT files")
        self.action_export_to_tiff_and_txt.triggered.connect(
            self.central_widget.left_panel.fit_maps_widget.pb_export_to_tiff_and_txt.clicked
        )

        xrfMaps = menubar.addMenu("XRF &Maps")
        xrfMaps.addAction(self.action_start_xrf_map_fitting)
        xrfMaps.addAction(self.action_compute_rois)
        xrfMaps.addSeparator()
        xrfMaps.addAction(self.action_load_quant_calibration)
        xrfMaps.addSeparator()
        xrfMaps.addAction(self.action_save_quant_calibration)
        xrfMaps.addAction(self.action_export_to_tiff_and_txt)

        # "View" menu item
        self.action_show_matplotlib_toolbar = QAction("Show &Matplotlib Toolbar", self)
        self.action_show_matplotlib_toolbar.setCheckable(True)
        self.action_show_matplotlib_toolbar.setChecked(True)
        self.action_show_matplotlib_toolbar.setStatusTip("Show Matplotlib Toolbar on the plots")
        self.action_show_matplotlib_toolbar.toggled.connect(self.action_show_matplotlib_toolbar_toggled)

        self.action_show_widget_tooltips = QAction("Show &Tooltips", self)
        self.action_show_widget_tooltips.setCheckable(True)
        self.action_show_widget_tooltips.setChecked(self.gui_vars["show_tooltip"])
        self.action_show_widget_tooltips.setStatusTip("Show widget tooltips")
        self.action_show_widget_tooltips.toggled.connect(self.action_show_widget_tooltips_toggled)

        options = menubar.addMenu("&Options")
        options.addAction(self.action_show_widget_tooltips)
        options.addAction(self.action_show_matplotlib_toolbar)

        # "Help" menu item
        self.action_online_docs = QAction("Online &Documentation", self)
        self.action_online_docs.setStatusTip("Open online documentation in the default browser")
        self.action_online_docs.triggered.connect(self.action_online_docs_triggered)

        self.action_about = QAction("&About PyXRF", self)
        self.action_about.setStatusTip("Show information about this program")
        self.action_about.triggered.connect(self.action_about_triggered)

        help = menubar.addMenu("&Help")
        help.addAction(self.action_online_docs)
        help.addSeparator()
        help.addAction(self.action_about)

        self.update_widget_state()

        # Connect signals
        self.central_widget.left_panel.load_data_widget.update_preview_map_range.connect(
            self.central_widget.right_panel.tab_preview_plots.preview_plot_count.update_map_range
        )

        # Before loading a new file or run
        self.central_widget.left_panel.load_data_widget.signal_loading_new_run.connect(
            self.central_widget.right_panel.slot_activate_tab_preview
        )

        # Open a new file or run
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.central_widget.left_panel.slot_activate_load_data_tab
        )
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.central_widget.right_panel.slot_activate_tab_preview
        )
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(self.slot_new_run_loaded)
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.wnd_image_wizard.slot_update_table
        )
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.central_widget.right_panel.tab_plot_xrf_maps.slot_update_dataset_info
        )
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.central_widget.right_panel.tab_plot_rgb_maps.slot_update_dataset_info
        )
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.wnd_load_quantitative_calibration.update_all_data
        )
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.central_widget.left_panel.fit_maps_widget.slot_update_for_new_loaded_run
        )

        # New model is loaded or processing parameters (incident energy) was changed
        self.central_widget.left_panel.model_widget.signal_incident_energy_or_range_changed.connect(
            self.central_widget.right_panel.tab_preview_plots.preview_plot_spectrum.redraw_preview_plot
        )
        self.central_widget.left_panel.model_widget.signal_incident_energy_or_range_changed.connect(
            self.wnd_manage_emission_lines.update_widget_data
        )
        self.central_widget.left_panel.model_widget.signal_incident_energy_or_range_changed.connect(
            self.central_widget.right_panel.tab_plot_fitting_model.redraw_plot_fit
        )

        self.central_widget.left_panel.model_widget.signal_model_loaded.connect(
            self.central_widget.right_panel.tab_preview_plots.preview_plot_spectrum.redraw_preview_plot
        )
        self.central_widget.left_panel.model_widget.signal_model_loaded.connect(
            self.central_widget.right_panel.slot_activate_tab_fitting_model
        )
        self.central_widget.left_panel.model_widget.signal_model_loaded.connect(
            self.central_widget.right_panel.tab_plot_fitting_model.update_controls
        )
        self.central_widget.left_panel.model_widget.signal_model_loaded.connect(
            self.wnd_manage_emission_lines.update_widget_data
        )

        # XRF Maps dataset changed
        self.central_widget.right_panel.tab_plot_xrf_maps.signal_maps_dataset_selection_changed.connect(
            self.wnd_image_wizard.slot_update_table
        )

        self.central_widget.right_panel.tab_plot_xrf_maps.signal_maps_dataset_selection_changed.connect(
            self.central_widget.right_panel.tab_plot_rgb_maps.combo_select_dataset_update_current_index
        )
        self.central_widget.right_panel.tab_plot_rgb_maps.signal_rgb_maps_dataset_selection_changed.connect(
            self.central_widget.right_panel.tab_plot_xrf_maps.combo_select_dataset_update_current_index
        )

        self.central_widget.right_panel.tab_plot_xrf_maps.signal_maps_norm_changed.connect(
            self.wnd_image_wizard.slot_update_ranges
        )

        # Quantitative calibration changed
        self.wnd_load_quantitative_calibration.signal_quantitative_calibration_changed.connect(
            self.central_widget.right_panel.tab_plot_rgb_maps.slot_update_ranges
        )
        self.wnd_load_quantitative_calibration.signal_quantitative_calibration_changed.connect(
            self.wnd_image_wizard.slot_update_ranges
        )

        # Selected element is changed (tools for emission line selection)
        self.wnd_manage_emission_lines.signal_selected_element_changed.connect(
            self.central_widget.right_panel.tab_plot_fitting_model.slot_selection_item_changed
        )
        self.central_widget.right_panel.tab_plot_fitting_model.signal_selected_element_changed.connect(
            self.wnd_manage_emission_lines.slot_selection_item_changed
        )
        self.central_widget.right_panel.tab_plot_fitting_model.signal_add_line.connect(
            self.wnd_manage_emission_lines.pb_add_eline_clicked
        )
        self.central_widget.right_panel.tab_plot_fitting_model.signal_remove_line.connect(
            self.wnd_manage_emission_lines.pb_remove_eline_clicked
        )
        self.wnd_manage_emission_lines.signal_update_element_selection_list.connect(
            self.central_widget.right_panel.tab_plot_fitting_model.slot_update_eline_selection_list
        )
        self.wnd_manage_emission_lines.signal_update_add_remove_btn_state.connect(
            self.central_widget.right_panel.tab_plot_fitting_model.slot_update_add_remove_btn_state
        )

        self.wnd_manage_emission_lines.signal_selected_element_changed.connect(
            self.central_widget.left_panel.model_widget.slot_selection_item_changed
        )
        self.central_widget.right_panel.tab_plot_fitting_model.signal_selected_element_changed.connect(
            self.central_widget.left_panel.model_widget.slot_selection_item_changed
        )

        # Total spectrum fitting completed
        self.central_widget.left_panel.model_widget.signal_total_spectrum_fitting_completed.connect(
            self.wnd_manage_emission_lines.update_eline_table
        )
        # Total spectrum invalidated
        self.wnd_manage_emission_lines.signal_parameters_changed.connect(
            self.central_widget.left_panel.model_widget.update_fit_status
        )
        # New dataset loaded or different channel selected. Compute fit parameters.
        self.central_widget.left_panel.load_data_widget.signal_data_channel_changed.connect(
            self.central_widget.left_panel.model_widget.clear_fit_status
        )
        self.central_widget.left_panel.load_data_widget.signal_new_run_loaded.connect(
            self.central_widget.left_panel.model_widget.clear_fit_status
        )
        self.central_widget.left_panel.model_widget.signal_incident_energy_or_range_changed.connect(
            self.central_widget.left_panel.model_widget.clear_fit_status
        )

        # Update map datasets (Fitted maps)
        self.central_widget.left_panel.fit_maps_widget.signal_map_fitting_complete.connect(
            self.central_widget.right_panel.tab_plot_xrf_maps.slot_update_dataset_info
        )
        self.central_widget.left_panel.fit_maps_widget.signal_map_fitting_complete.connect(
            self.central_widget.right_panel.tab_plot_rgb_maps.slot_update_dataset_info
        )
        self.central_widget.left_panel.fit_maps_widget.signal_activate_tab_xrf_maps.connect(
            self.central_widget.right_panel.slot_activate_tab_xrf_maps
        )

        # Update map datasets (ROI maps)
        self.wnd_compute_roi_maps.signal_roi_computation_complete.connect(
            self.central_widget.right_panel.tab_plot_xrf_maps.slot_update_dataset_info
        )
        self.wnd_compute_roi_maps.signal_roi_computation_complete.connect(
            self.central_widget.right_panel.tab_plot_rgb_maps.slot_update_dataset_info
        )
        self.wnd_compute_roi_maps.signal_activate_tab_xrf_maps.connect(
            self.central_widget.right_panel.slot_activate_tab_xrf_maps
        )

        self.signal_fitting_parameters_changed.connect(self.wnd_general_fitting_settings.update_form_data)
        self.signal_fitting_parameters_changed.connect(self.wnd_fitting_parameters_shared.update_form_data)
        self.signal_fitting_parameters_changed.connect(self.wnd_fitting_parameters_lines.update_form_data)
        self.signal_fitting_parameters_changed.connect(self.wnd_manage_emission_lines.update_widget_data)

    @Slot()
    @Slot(str)
    def update_widget_state(self, condition=None):
        # Update the state of the menu bar
        state = not self.gui_vars["gui_state"]["running_computations"]
        self.menuBar().setEnabled(state)

        state_computations = self.gui_vars["gui_state"]["running_computations"]
        if state_computations:
            if not self._cursor_set:
                QGuiApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
                self._cursor_set = True
        else:
            if self._cursor_set:
                QGuiApplication.restoreOverrideCursor()
                self._cursor_set = False

        # Forward to children
        self.central_widget.update_widget_state(condition)

        # Forward the updates to open windows
        self.wnd_manage_emission_lines.update_widget_state(condition)
        self.wnd_compute_roi_maps.update_widget_state(condition)
        self.wnd_image_wizard.update_widget_state(condition)
        self.wnd_load_quantitative_calibration.update_widget_state(condition)
        self.wnd_general_fitting_settings.update_widget_state(condition)
        self.wnd_fitting_parameters_shared.update_widget_state(condition)
        self.wnd_fitting_parameters_lines.update_widget_state(condition)

    def closeEvent(self, event):
        mb_close = QMessageBox(
            QMessageBox.Question,
            "Exit",
            "Are you sure you want to EXIT the program?",
            QMessageBox.Yes | QMessageBox.No,
            parent=self,
        )
        mb_close.setDefaultButton(QMessageBox.No)

        if mb_close.exec() == QMessageBox.Yes:
            event.accept()

            self.wnd_manage_emission_lines.close()
            self.wnd_compute_roi_maps.close()
            self.wnd_image_wizard.close()
            self.wnd_load_quantitative_calibration.close()
            self.wnd_general_fitting_settings.close()
            self.wnd_fitting_parameters_shared.close()
            self.wnd_fitting_parameters_lines.close()

            # This flag is used for CI tests
            self._is_closed = True
        else:
            event.ignore()

    def action_online_docs_triggered(self):
        """
        Display online documentation: open the URL in the default browser.
        """
        doc_url = "http://nsls-ii.github.io/PyXRF/"
        try:
            webbrowser.open(doc_url, autoraise=True)
        except Exception as ex:
            logger.error(f"Error occurred while opening URL '{doc_url}' in the default browser")
            msg = f"Failed to Open Online Documentation. \n  Exception: {str(ex)}"
            msgbox = QMessageBox(QMessageBox.Critical, "Error", msg, QMessageBox.Ok, parent=self)
            msgbox.exec()

    def action_about_triggered(self):
        """
        Display 'About' dialog box
        """
        dlg = DialogAbout()
        dlg.exec()

    def action_show_matplotlib_toolbar_toggled(self, state):
        """
        Turn tooltips on or off
        """
        self.gui_vars["show_matplotlib_toolbar"] = state
        self.update_widget_state()

    def action_show_widget_tooltips_toggled(self, state):
        """
        Turn tooltips on or off
        """
        self.gui_vars["show_tooltip"] = state
        self.update_widget_state("tooltips")

    @Slot()
    def update_window_title(self):
        self.setWindowTitle(self.gpc.get_window_title())

    @Slot(bool)
    def slot_new_run_loaded(self, success):
        if success:
            # Update status bar
            file_name = self.gpc.get_loaded_file_name()
            run_id, run_uid = "", ""
            if self.gpc.is_scan_metadata_available():
                try:
                    run_id = self.gpc.get_metadata_scan_id()
                except Exception:
                    pass
                try:
                    run_uid = self.gpc.get_metadata_scan_uid()
                except Exception:
                    pass
            else:
                if self.gpc.get_current_run_id() >= 0:
                    run_id = self.gpc.get_current_run_id()
            s = ""
            if run_id:
                s += f"ID: {run_id}  "
            if run_uid:
                if run_id:
                    s += f"({run_uid})  "
                else:
                    s += f"UID: {run_uid}  "
            if file_name:
                s += f"File: '{file_name}'"
            self._set_status_bar_text(s)

            # Activate/deactivate "View Metadata ..." menu item
            if self.gpc.is_scan_metadata_available():
                self.action_view_metadata.setEnabled(True)
            else:
                self.action_view_metadata.setEnabled(False)

        else:
            self._set_status_bar_text()

    def _set_status_bar_text(self, text=None):
        if text is None:
            text = self.statusLabelDefaultText
        self.statusLabel.setText(text)
Exemplo n.º 31
0
    def getMenuAction(self, menu, title='notitle', action_name='noaction',
                      args=[], kwargs={}):
        # ToDo: Clean this up, it is very hacky
        env = {'app': QApplication.instance(),
               'win': self,
               'action': actions,
               }

        if action_name is not None:

            if action_name.startswith('settings.'):
                setting_id = action_name[len('settings.'):]
                setting = getSetting(setting_id)

                if setting:
                    if setting.enum_options is not None:
                        submenu = QMenu(parent=self, title=title)

                        group = QActionGroup(self)
                        group.setExclusive(True)
                        group.triggered.connect(lambda a: setting.setValue(a.data()))

                        def update(group, val):
                            for act in group.actions():
                                if act.data() == val:
                                    act.setChecked(True)
                                    break

                        for num, opt in enumerate(setting.enum_options):

                            act = QAction(parent=self, text=opt)
                            act.setCheckable(True)
                            if setting.value == num:
                                act.setChecked(True)

                            act.setData(num)
                            setting.notify(lambda v: update(group, v))

                            act.setActionGroup(group)
                            submenu.addAction(act)
                        menu.addMenu(submenu)

                    elif setting.value_type == bool:
                        # works for bool settings
                        menu_action = QAction(parent=self, text=title)
                        menu_action.setCheckable(True)
                        menu_action.triggered.connect(setting.setValue)
                        setting.notify(menu_action.setChecked)
                        menu.addAction(menu_action)

                    return

            try:
                menu_action = QAction(parent=self, text=title)

                mod, action = action_name.split('.', 1)
                method = getattr(env.get(mod, self), action)
                if menu_action.isCheckable():
                    menu_action.triggered.connect(method)
                else:
                    menu_action.triggered.connect(lambda checked: method(*args, **kwargs))

                menu.addAction(menu_action)
                return
            except:
                pass

            try:
                menu_action = QAction(parent=self, text=title)
                actions.bindWidget(menu_action, action_name)
                menu.addAction(menu_action)
                return
            except actions.InvalidAction:
                LOG.exception('Error binding menu action %s', action_name)

        menu_action = QAction(parent=self, text=title)
        msg = "The <b>{}</b> action specified for the " \
              "<b>{}</b> menu item could not be triggered. " \
              "Check the YAML config file for errors." \
              .format(action_name or '', title.replace('&', ''))
        menu_action.triggered.connect(lambda: QMessageBox.critical(self, "Menu Action Error!", msg))
        menu.addAction(menu_action)
Exemplo n.º 32
0
    class PlotMainWindow(QWidget):
        """Base class for plot main windows."""
        def __init__(self, U, plot, length=1, title=None):
            super().__init__()

            layout = QVBoxLayout()

            if title:
                title = QLabel('<b>' + title + '</b>')
                title.setAlignment(Qt.AlignHCenter)
                layout.addWidget(title)
            layout.addWidget(plot)

            plot.set(U, 0)

            if length > 1:
                hlayout = QHBoxLayout()

                self.slider = QSlider(Qt.Horizontal)
                self.slider.setMinimum(0)
                self.slider.setMaximum(length - 1)
                self.slider.setTickPosition(QSlider.TicksBelow)
                hlayout.addWidget(self.slider)

                lcd = QLCDNumber(m.ceil(m.log10(length)))
                lcd.setDecMode()
                lcd.setSegmentStyle(QLCDNumber.Flat)
                hlayout.addWidget(lcd)

                layout.addLayout(hlayout)

                hlayout = QHBoxLayout()

                toolbar = QToolBar()
                self.a_play = QAction(
                    self.style().standardIcon(QStyle.SP_MediaPlay), 'Play',
                    self)
                self.a_play.setCheckable(True)
                self.a_rewind = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSeekBackward),
                    'Rewind', self)
                self.a_toend = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSeekForward),
                    'End', self)
                self.a_step_backward = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSkipBackward),
                    'Step Back', self)
                self.a_step_forward = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSkipForward),
                    'Step', self)
                self.a_loop = QAction(
                    self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop',
                    self)
                self.a_loop.setCheckable(True)
                toolbar.addAction(self.a_play)
                toolbar.addAction(self.a_rewind)
                toolbar.addAction(self.a_toend)
                toolbar.addAction(self.a_step_backward)
                toolbar.addAction(self.a_step_forward)
                toolbar.addAction(self.a_loop)
                if hasattr(self, 'save'):
                    self.a_save = QAction(
                        self.style().standardIcon(QStyle.SP_DialogSaveButton),
                        'Save', self)
                    toolbar.addAction(self.a_save)
                    self.a_save.triggered.connect(self.save)
                hlayout.addWidget(toolbar)

                self.speed = QSlider(Qt.Horizontal)
                self.speed.setMinimum(0)
                self.speed.setMaximum(100)
                hlayout.addWidget(QLabel('Speed:'))
                hlayout.addWidget(self.speed)

                layout.addLayout(hlayout)

                self.timer = QTimer()
                self.timer.timeout.connect(self.update_solution)

                self.slider.valueChanged.connect(self.slider_changed)
                self.slider.valueChanged.connect(lcd.display)
                self.speed.valueChanged.connect(self.speed_changed)
                self.a_play.toggled.connect(self.toggle_play)
                self.a_rewind.triggered.connect(self.rewind)
                self.a_toend.triggered.connect(self.to_end)
                self.a_step_forward.triggered.connect(self.step_forward)
                self.a_step_backward.triggered.connect(self.step_backward)

                self.speed.setValue(50)

            elif hasattr(self, 'save'):
                hlayout = QHBoxLayout()
                toolbar = QToolBar()
                self.a_save = QAction(
                    self.style().standardIcon(QStyle.SP_DialogSaveButton),
                    'Save', self)
                toolbar.addAction(self.a_save)
                hlayout.addWidget(toolbar)
                layout.addLayout(hlayout)
                self.a_save.triggered.connect(self.save)

            self.setLayout(layout)
            self.plot = plot
            self.U = U
            self.length = length

        def slider_changed(self, ind):
            self.plot.set(self.U, ind)

        def speed_changed(self, val):
            self.timer.setInterval(val * 20)

        def update_solution(self):
            ind = self.slider.value() + 1
            if ind >= self.length:
                if self.a_loop.isChecked():
                    ind = 0
                else:
                    self.a_play.setChecked(False)
                    return
            self.slider.setValue(ind)

        def toggle_play(self, checked):
            if checked:
                if self.slider.value() + 1 == self.length:
                    self.slider.setValue(0)
                self.timer.start()
            else:
                self.timer.stop()

        def rewind(self):
            self.slider.setValue(0)

        def to_end(self):
            self.a_play.setChecked(False)
            self.slider.setValue(self.length - 1)

        def step_forward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() + 1
            if ind == self.length and self.a_loop.isChecked():
                ind = 0
            if ind < self.length:
                self.slider.setValue(ind)

        def step_backward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() - 1
            if ind == -1 and self.a_loop.isChecked():
                ind = self.length - 1
            if ind >= 0:
                self.slider.setValue(ind)