def _get_checked_items(self, qlist: QListWidget):
     items = []
     for i in range(qlist.count()):
         item = qlist.item(i)
         if item.checkState() == Qt.Checked:
             items.append(item)
     return items
def add_fields_to_component(component: Group,
                            fields_widget: QListWidget,
                            component_model: NexusTreeModel = None):
    """
    Adds fields from a list widget to a component.
    :param component: Component to add the field to.
    :param fields_widget: The field list widget to extract field information such the name and value of each field.
    """
    for i in range(fields_widget.count()):
        widget = fields_widget.itemWidget(fields_widget.item(i))
        try:
            if not isinstance(widget.value, (Link, Dataset)):
                stream_module = deepcopy(widget.value)
                stream_module.parent_node = component
                component.children.append(stream_module)
            else:
                component[widget.name] = widget.value
        except ValueError as error:
            show_warning_dialog(
                f"Warning: field {widget.name} not added",
                title="Field invalid",
                additional_info=str(error),
                parent=fields_widget.parent().parent(),
            )
    if component_model and component_model.current_nxs_obj[1]:
        row = component_model.rowCount(component_model.current_nxs_obj[1])
        component_model.createIndex(row, 0, component_model.current_nxs_obj[1])
Example #3
0
class SignalGrouper(QDialog):
    def __init__(self, chartData, parent=None):
        QDialog.__init__(self, parent)
        self.chartData = chartData
        self._create()

    def _create(self):
        self.mLayout = QVBoxLayout(self)
        
        self.gSelector = QListWidget()
        groups = self.chartData.getDataGroups()
        self.gSelector.addItems(groups)
        self.gSelector.currentTextChanged.connect(self._updateGroupList)
        self.chartData.dataGroupAdded.connect(self.gSelector.addItem)
        self.chartData.dataGroupAdded.connect(self.gSelector.addItem)
        self.mLayout.addWidget(self.gSelector)

        self.sSelector = QListWidget()
        self.mLayout.addWidget(self.sSelector)

        groupBtn = QPushButton('Create group from selected')
        groupBtn.clicked.connect(self.createNewGroup)
        self.mLayout.addWidget(groupBtn)
        

    def _updateGroupList(self):
        newGroup = self.gSelector.currentItem().text()
        sStruct = self.chartData[newGroup].getColStructure()
        self.sSelector.clear()
        for ws in sStruct:
            firstChannel = sStruct[ws][0]
            isOneSignal = self.chartData[newGroup][firstChannel][ws][0]
            if isOneSignal:
                item = QListWidgetItem(ws, self.sSelector)
                item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
                item.setCheckState(Qt.Unchecked)

    def createNewGroup(self):
        checkList = []
        for i in range(self.sSelector.count()):
            sItem = self.sSelector.item(i)
            if sItem.checkState() == Qt.Checked:
                checkList.append(sItem.text())
        if len(checkList) > 0:
            groupName, result = QInputDialog().getText(self, 'Input', 'Enter group name:')
            if result:
                ws = self.gSelector.currentItem().text()
                sStruct = self.chartData[ws].getColStructure(checkList)
                sKeys = list(sStruct.keys())
                for s in range(len(sKeys)):
                    if sStruct[sKeys[s]] != sStruct[sKeys[s-1]]:
                        print('Signals have diffrent channel sets')
                        return
                self.chartData.appendSignalGroup(ws, groupName, sStruct[sKeys[0]], checkList)
            else:
                return
        else:
            return
    def gather_all_selected_track(list_widget: QListWidget,
                                  file_controller: FileController):

        user_selected_track = []
        for index in range(list_widget.count()):

            item = list_widget.item(index)
            if item.checkState() == PySide2.QtCore.Qt.Checked:
                user_selected_track.append(file_controller.get_track(index))

        return user_selected_track
Example #5
0
    def gather_all_selected_track(self, list_1: QListWidget,
                                  list_2: QListWidget):

        self._user_settings_1 = []
        self._user_settings_2 = []
        logger.debug("Gathering selected tracks")

        for index in range(list_1.count()):

            item = list_1.item(index)
            if item.checkState() == PySide2.QtCore.Qt.Checked:
                self._user_settings_1.append(index)

        logger.debug("Reference 1 Tracks : " +
                     str(self._user_settings_1).strip('[]'))

        for index in range(list_2.count()):

            item = list_2.item(index)
            if item.checkState() == PySide2.QtCore.Qt.Checked:
                self._user_settings_2.append(index)

        logger.debug("Reference 2 Tracks : " +
                     str(self._user_settings_2).strip('[]'))
class FieldAttrsDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setLayout(QGridLayout())
        self.setWindowTitle("Edit Attributes")

        self.list_widget = QListWidget()
        self.list_widget.setMinimumSize(800, 600)
        self.add_button = QPushButton("Add attr")
        self.add_button.clicked.connect(self.__add_attr)
        self.remove_button = QPushButton("Remove attr")
        self.remove_button.clicked.connect(self._remove_attrs)

        self.layout().addWidget(self.list_widget, 0, 0, 2, 1)
        self.layout().addWidget(self.add_button, 0, 1)
        self.layout().addWidget(self.remove_button, 1, 1)

    def fill_existing_attrs(self, existing_dataset: h5py.Dataset):
        for name, value in existing_dataset.attrs.items():
            if name not in ATTRS_BLACKLIST:
                frame = FieldAttrFrame(name, value)
                self._add_attr(existing_frame=frame)

    def __add_attr(self):
        """
        Only used for button presses. Any additional arguments from the signal are ignored.
        """
        self._add_attr()

    def _add_attr(self, existing_frame=None):
        item = QListWidgetItem()
        self.list_widget.addItem(item)
        frame = existing_frame if existing_frame is not None else FieldAttrFrame(
        )
        item.setSizeHint(frame.sizeHint())
        self.list_widget.setItemWidget(item, frame)

    def _remove_attrs(self):
        for index in self.list_widget.selectedIndexes():
            self.list_widget.takeItem(index.row())

    def get_attrs(self):
        attrs_dict = {}
        for index in range(self.list_widget.count()):
            item = self.list_widget.item(index)
            widget = self.list_widget.itemWidget(item)
            attrs_dict[widget.value[0]] = widget.value[1]
        return attrs_dict
Example #7
0
class SimpleTodoPlus(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.todo_list_widget = QListWidget(self)
        self.todo_list_widget.itemChanged.connect(self.onItemChanged)

        self.add_todo_btn = QPushButton("Add Todo", self)
        self.add_todo_btn.clicked.connect(self.add_todo_btn_clicked)

        self.remove_todo_btn = QPushButton("Remove Todo", self)
        self.remove_todo_btn.clicked.connect(self.remove_todo_btn_clicked)

        self.clear_todo_btn = QPushButton("Clear Todo", self)
        self.clear_todo_btn.clicked.connect(self.clear_todo_btn_clicked)

        vbox_layout = QVBoxLayout(self)
        vbox_layout.addWidget(self.todo_list_widget)

        hbox_layout = QHBoxLayout()
        hbox_layout.addWidget(self.add_todo_btn)
        hbox_layout.addWidget(self.remove_todo_btn)
        hbox_layout.addWidget(self.clear_todo_btn)

        vbox_layout.addLayout(hbox_layout)

    def add_todo_btn_clicked(self):
        item = QListWidgetItem(f"Todo {self.todo_list_widget.count() + 1}")
        item.setFlags(item.flags() | Qt.ItemIsUserCheckable
                      | Qt.ItemIsEditable)
        item.setCheckState(Qt.Unchecked)
        self.todo_list_widget.addItem(item)
        self.todo_list_widget.edit(self.todo_list_widget.indexFromItem(item))

    def remove_todo_btn_clicked(self):
        if self.todo_list_widget.count():
            self.todo_list_widget.takeItem(self.todo_list_widget.currentRow())

    def clear_todo_btn_clicked(self):
        self.todo_list_widget.clear()

    def onItemChanged(self, item):
        font = item.font()
        font.setStrikeOut(item.checkState() == Qt.Checked)
        item.setFont(font)
def add_fields_to_component(component: Component, fields_widget: QListWidget):
    """
    Adds fields from a list widget to a component.
    :param component: Component to add the field to.
    :param fields_widget: The field list widget to extract field information such the name and value of each field.
    """
    for i in range(fields_widget.count()):
        widget = fields_widget.itemWidget(fields_widget.item(i))
        try:
            component.set_field(
                name=widget.name, value=widget.value, dtype=widget.dtype
            )
        except ValueError as error:
            show_warning_dialog(
                f"Warning: field {widget.name} not added",
                title="Field invalid",
                additional_info=str(error),
                parent=fields_widget.parent().parent(),
            )
Example #9
0
class AbstractMultiInputPage(EnableNextOnBackMixin, QWizardPage):
    def __init__(self, parent):
        QWizardPage.__init__(self, parent)
        self.parent_wizard = weakref.proxy(parent)

        self.label = QLabel()
        self.line_edit = QLineEdit()
        self.line_edit.returnPressed.connect(self.add_item)
        self.add_button = QPushButton()
        self.add_button.clicked.connect(self.add_item)

        self.list = QListWidget()
        self.delete_button = QPushButton('&Delete')
        self.delete_button.setDisabled(True)
        self.delete_button.clicked.connect(self.delete_item)

        grid = QGridLayout(self)
        grid.addWidget(self.label, 0, 0)
        grid.addWidget(self.line_edit, 0, 1)
        grid.addWidget(self.add_button, 0, 2)
        grid.addWidget(self.list, 1, 0, 1, 2)
        grid.addWidget(self.delete_button, 1, 2, 1, 1, Qt.AlignTop)

        self.setLayout(grid)

    def initializePage(self):
        if self.list.count() == 0:
            self.parent_wizard.next_button.setDisabled(True)

    def add_item(self):
        if not (name := self.line_edit.text()):
            return
        item = QListWidgetItem(name)
        self.list.addItem(item)
        self.matrix_add(name)
        self.line_edit.clear()
        self.line_edit.setFocus()
        self.parent_wizard.next_button.setEnabled(True)
        self.delete_button.setEnabled(True)
Example #10
0
class ContinuousCriteriaPage(EnableNextOnBackMixin, QWizardPage):
    def __init__(self, parent):
        super().__init__(parent)
        self.parent_wizard = weakref.proxy(parent)

        self.setTitle('Continuous criteria')
        # Radio button, if yes then ask for inputs
        self.yes = QRadioButton(
            '&Yes, there are criteria that needs to be calculated')
        no = QRadioButton(
            'N&o, I will manually give a rating for every choice and criteria')
        no.setChecked(True)

        self.registerField('yes', self.yes)
        self.yes.toggled.connect(self.toggled)

        group = QButtonGroup(self)
        group.addButton(self.yes)
        group.addButton(no)

        # Duplicated from AbstractMultiInputPage
        self.line_edit = QLineEdit()
        self.list_widget = QListWidget()
        self.add_button = QPushButton('&Add criterion')
        self.delete_button = QPushButton('&Delete')

        self.line_edit.setDisabled(True)
        self.list_widget.setDisabled(True)
        self.add_button.setDisabled(True)
        self.delete_button.setDisabled(True)

        self.line_edit.returnPressed.connect(self.add_item)
        self.add_button.clicked.connect(self.add_item)
        self.delete_button.clicked.connect(self.delete_item)

        grid = QGridLayout(self)
        grid.addWidget(self.yes, 0, 0)
        grid.addWidget(no, 1, 0)
        grid.addWidget(self.line_edit, 2, 0)
        grid.addWidget(self.add_button, 2, 1)
        grid.addWidget(self.list_widget, 3, 0)
        grid.addWidget(self.delete_button, 3, 1, Qt.AlignTop)
        self.setLayout(grid)

    def initializePage(self):
        for criterion in self.parent_wizard.main_parent.matrix.continuous_criteria:
            self.list_widget.addItem(QListWidgetItem(criterion))

        if self.list_widget.count() != 0:
            self.yes.setChecked(True)
            self.parent_wizard.next_button.setEnabled(True)

    def toggled(self, checked: bool):
        if checked:
            self.line_edit.setEnabled(True)
            self.list_widget.setEnabled(True)
            self.add_button.setEnabled(True)
            self.parent_wizard.next_button.setDisabled(True)
        else:
            self.line_edit.setDisabled(True)
            self.list_widget.setDisabled(True)
            self.parent_wizard.next_button.setEnabled(True)

    def add_item(self):
        # Duplicated
        if not (name := self.line_edit.text()):
            return
        item = QListWidgetItem(name)
        self.list_widget.addItem(item)
        self.line_edit.clear()
        self.line_edit.setFocus()
        self.parent_wizard.next_button.setEnabled(True)
        self.delete_button.setEnabled(True)

        self.parent_wizard.main_parent.line_edit_cc_tab.setText(name)
        self.parent_wizard.main_parent.matrix.add_continuous_criterion(
            name, weight=float('nan'))
        self.parent_wizard.main_parent.add_continuous_criteria()
Example #11
0
class PlaylistWidget(QWidget):
    itemPlayed = Signal(list)

    def __init__(self):
        super().__init__()

        self.layout = QVBoxLayout()

        self.open_playlist_btn = QPushButton("Open Playlist")
        self.playlist_list = QListWidget()

        self.setAcceptDrops(True)

        self.layout.addWidget(self.open_playlist_btn)
        self.layout.addWidget(self.playlist_list)

        self.open_playlist_btn.clicked.connect(self.open_playlist)
        self.playlist_list.itemDoubleClicked.connect(
            self.on_playlist_list_doubleclick)

        self.setLayout(self.layout)

    def open_playlist(self):
        filename = QFileDialog.getOpenFileName(self, "Select a playlist")
        if filename[0]:
            self.load_playlist(filename[0])

    def load_playlist(self, playlist_filepath):
        self.clear_playlist()

        p = Playlist.load_from_file(playlist_filepath)
        playlist_item_widget_list = [
            PlaylistItemWidget(playlist_item)
            for playlist_item in p.playlist_content
        ]
        for playlist_item in playlist_item_widget_list:
            self.playlist_list.addItem(playlist_item)

    def load_playlist_item(self, playlist_item_widget):
        self.itemPlayed.emit(playlist_item_widget.playlist_item.media_list)

    def clear_playlist(self):
        while self.playlist_list.count() > 0:
            item = self.playlist_list.takeItem(0)

    def on_playlist_list_doubleclick(self, playlist_item):
        self.load_playlist_item(playlist_item)

    def dragEnterEvent(self, event: PySide2.QtGui.QDragEnterEvent) -> None:
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event: PySide2.QtGui.QDropEvent) -> None:
        if event.mimeData().hasUrls:
            event.setDropAction(Qt.CopyAction)
            event.accept()

            if len(event.mimeData().urls()) > 0:
                url = event.mimeData().urls()[0]
                self.load_playlist(url.toLocalFile())
        else:
            event.ignore()
Example #12
0
from PySide2 import QtCore
from PySide2.QtWidgets import QApplication, QListWidget, QComboBox

if __name__ == '__main__':
    """
    Two views using each one a instance of our data
    When the data is change in QListWidget(), the data in QComboBox will not be changed
    """

    app = QApplication(sys.argv)

    # Let's make the QListWidget show this data
    data = ["ONE", "TWO", "THREE", "FOUR", "FIVE"]

    list_widget = QListWidget()
    list_widget.show()
    list_widget.addItems(data)

    # Let's make elements on QListWidget editable
    for index in range(list_widget.count()):
        item = list_widget.item(index)
        item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)

    # A comboBox showing the same data
    comboBox = QComboBox()
    comboBox.show()
    comboBox.addItems(data)

    sys.exit(app.exec_())
Example #13
0
class Widget(QWidget):

    def __init__(self):
        QWidget.__init__(self)

        # Data for plotting and marker data storage
        self.data = {}
        self.slice_index = {
            'ind1': 0, 
            'ind2': 0
            }
        self.marker_id = 0
        self.marker_ind = []
        self.marker_setpoint = {
            'Marker1': 0, 
            'Marker2': 0, 
            }

        # Error message dialog widget
        self.error_popup = QErrorMessage()
        self.error_popup.setWindowTitle('Snap file error')

        # Left (List of Checkboxes)
        self.list_widget = QListWidget()
        #Resize width and height
        self.list_widget.setSizePolicy(QSizePolicy.Preferred, 
                                       QSizePolicy.Preferred)
        self.list_widget.setMinimumWidth(200)
        self.list_widget.setMaximumWidth(400)
        # self.list_widget.setMinimumHeight(300)
        self.list_widget.setMaximumHeight(500)

        # Signal groupbox
        self.signal_groupbox = QGroupBox('Available Signals')
        self.signal_groupbox.setMinimumWidth(200)
        self.signal_groupbox.setMaximumWidth(350)
        self.signal_groupbox.setMinimumHeight(100)
        self.sig_group_layout = QVBoxLayout()
        self.signal_groupbox.setLayout(self.sig_group_layout)
        # Statistics groupbox
        self.stats_groupbox = QGroupBox('Statistics')
        self.stats_groupbox.setMinimumWidth(200)
        self.stats_groupbox.setMaximumWidth(350)
        self.stats_groupbox.setMinimumHeight(240)
        self.stats_group_layout = QFormLayout()

        # Label initiation
        # Marker Time 1
        self.mark_one_time_label = QLabel('Marker1_time: ')
        self.mark_one_time_value = QLabel()
        # Marker Time 2
        self.mark_two_time_label = QLabel('Marker2_time: ')
        self.mark_two_time_value = QLabel()
        # On/Off labels for 0/1 signals counter
        self.on_off_label = QLabel('On/Off: ')
        self.on_off_value = QLabel()
        # Mean value
        self.mean_label = QLabel('Mean: ')
        self.mean_value = QLabel()
        # Standard deviation
        self.std_label = QLabel('Sigma(STD): ')
        self.std_value = QLabel()
        # Minimal value
        self.min_label = QLabel('Min: ')
        self.min_value = QLabel()
        # Maximual value
        self.max_label = QLabel('Max: ')
        self.max_value = QLabel()
        # Max - Min value
        self.val_diff_label = QLabel('Max-Min: ')
        self.val_diff_value = QLabel()
        # Time difference (X-axis)
        self.time_diff_label = QLabel('Time_diff: ')
        self.time_diff_value = QLabel('')

        # Row addition of labels
        self.stats_group_layout.addRow(self.mark_one_time_label, 
                                       self.mark_one_time_value)
        self.stats_group_layout.addRow(self.mark_two_time_label,
                                       self.mark_two_time_value)
        self.stats_group_layout.addRow(self.time_diff_label, 
                                       self.time_diff_value)
        self.stats_group_layout.addRow(self.on_off_label, self.on_off_value)
        self.stats_group_layout.addRow(self.mean_label, self.mean_value)
        self.stats_group_layout.addRow(self.std_label, self.std_value)
        self.stats_group_layout.addRow(self.min_label, self.min_value)
        self.stats_group_layout.addRow(self.max_label, self.max_value)
        self.stats_group_layout.addRow(self.val_diff_label, 
                                       self.val_diff_value)
        self.stats_groupbox.setLayout(self.stats_group_layout)

        # Set markers section of the application (bottom left)
        self.marker_grid = QGridLayout()
        self.marker_one_notice = QLabel()
        self.marker_two_notice = QLabel()
        self.set_marker_one_label = QLabel('Set Marker1:')
        self.set_marker_two_label = QLabel('Set Marker2:')
        self.set_marker_one_value = QLineEdit()
        self.set_marker_one_value.setMaximumWidth(100)
        self.set_marker_two_value = QLineEdit()
        self.set_marker_two_value.setMaximumWidth(100)

        self.marker_grid.addWidget(self.set_marker_one_label)
        self.marker_grid.addWidget(self.set_marker_one_value)
        self.marker_grid.addWidget(self.marker_one_notice)
        self.marker_grid.addWidget(self.set_marker_two_label)
        self.marker_grid.addWidget(self.set_marker_two_value)
        self.marker_grid.addWidget(self.marker_two_notice)
                                        
        # Leftside app layout
        self.v_layout = QVBoxLayout()
        self.v_layout.addWidget(self.list_widget)
        self.v_layout.addWidget(self.signal_groupbox)
        self.v_layout.addWidget(self.stats_groupbox)
        self.v_layout.addLayout(self.marker_grid)

        # Matplotlib figure
        self.fig = Figure(figsize=(5, 3))
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(QSizePolicy.Expanding, 
                                  QSizePolicy.Expanding)
        self.ax = self.canvas.figure.subplots()
        self.ax.grid()
        self.ax.set_xlabel('Time[s]')
        self.fig.suptitle('Parameter Plot')
      
        # QWidget Layout
        self.h_layout = QHBoxLayout()
        self.h_layout.addLayout(self.v_layout)
        self.h_layout.addWidget(self.canvas)

        # Set the layout to the QWidget
        self.setLayout(self.h_layout)

        # ListWidget and plot connections
        self.list_widget.itemChanged.connect(self.item_changed)
        self.click_event = self.fig.canvas.mpl_connect('button_press_event',
                                                       self.on_click)
        self.set_marker_one_value.returnPressed.connect(
                                                lambda: self.add_marker('one'))
        self.set_marker_two_value.returnPressed.connect(
                                                lambda: self.add_marker('two'))
        
    # Add radio button when signal is checked for plotting
    def add_radio_button(self, name):
        self.rad_btn = QRadioButton(name)
        self.rad_btn.toggled.connect(self.calculate_signal_stats)
        self.sig_group_layout.addWidget(self.rad_btn)

    # Remove radio button when signal is unchecked for plotting
    def remove_radio_button(self, name):
        for item in self.signal_groupbox.children():
            try:
                if item.text() == name:
                    item.setParent(None)
            except AttributeError:
                pass
    
    # Remove all radiobuttons on new data load
    def clear_signals(self):
        count = 0
        for item in self.signal_groupbox.children():
            if count == 0:
                count = 1
                continue 
            else:
                item.setParent(None)  
    # Check state of all radiobuttons, if none is checked remove stats values
    def check_signals(self):
        count = 0
        num_of_check = 0
        for item in self.signal_groupbox.children():
            if count == 0:
                count = 1
                continue 
            else:
                if item.isChecked():
                    num_of_check += 1
        # If no radiobuttons are checked, remove stats
        if num_of_check == 0:
            self.mean_value.setText('') 
            self.std_value.setText('') 
            self.max_value.setText('') 
            self.min_value.setText('') 
            self.val_diff_value.setText('') 
            self.on_off_value.setText('')               

    # Item additon of listWidget
    def fill_list(self, list_items):
        self.list_widget.clear()

        for column in list_items:
            item = QListWidgetItem(column)
            item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
            item.setCheckState(Qt.Unchecked)
            self.list_widget.addItem(item)

        self.show()
    
    # If new data is loaded, replace the old one
    def replace_data(self, temp):
        if not temp == self.data:
            self.data = temp
            self.clear_signals()

    @Slot()
    # Item state changed in listWidget event handler
    def item_changed(self, item):
        if item.checkState() == Qt.Unchecked:
           self.remove_plot(item.text())
           self.remove_radio_button(item.text())
           self.check_signals()
        else:
            self.add_plot(self.data['Time'], 
                          self.data[item.text()], item.text())
            self.add_radio_button(item.text())
                
    # Method for plotting data
    def add_plot(self, x_data, y_data, name):
        self.ax.plot(x_data, y_data, label=name, picker=3)
        self.ax.grid(True)
        self.ax.relim()
        self.ax.set_xlabel('Time[s]')
        self.ax.autoscale_view()
        self.ax.legend(loc='upper right')
        self.canvas.draw()

    # Method for marker addition via QLineEdit
    def add_marker(self, label):
        # Check if any signal is plotted
        sig_count = 0
        for i in range(self.list_widget.count()):
            if self.list_widget.item(i).checkState() == Qt.Checked:
                sig_count += 1

        if sig_count == 0:
            self.marker_one_notice.setText('No active signal!')
            self.marker_two_notice.setText('No active signal!')
            return
        try:
            max_time = self.data['Time'][-1]
            min_time = self.data['Time'][0]
        except KeyError:
            self.marker_one_notice.setText('Signal data not loaded!')
            self.marker_two_notice.setText('Signal data not loaded!')
        if label == 'one':
            try:
                mark1_value = float(self.set_marker_one_value.text())
                if mark1_value < max_time and mark1_value > min_time:
                    if self.marker_id == 0:
                        self.marker_id += 1
                        label_id = self.marker_id
                    elif self.marker_id == 1:
                        self.marker_id += 1
                        label_id = self.marker_id
                        self.remove_marker('first')
                    else:
                        self.remove_marker('first')
                        label_id = 1

                    self.marker_one_notice.setText('')
                    self.marker_setpoint['Marker1'] = mark1_value
                    self.mark_one_time_value.setText(
                                            self.set_marker_one_value.text())
                    self.calculate_marker_stats()
                    self.calculate_signal_stats()
                    
                    # Draw the marker
                    L =  self.ax.axvline(
                                    x=float(self.set_marker_one_value.text()), 
                                    linestyle='dashed', 
                                    color='red', 
                                    label='_Marker' + str(label_id))
                    self.fig.canvas.draw()
                else:
                    self.marker_one_notice.setText('Marker1 out of bounds')
            except ValueError:
                self.marker_one_notice.setText('Non-Valid value entered!')
        else:
            try:
                mark2_value = float(self.set_marker_two_value.text()) 
                if mark2_value < max_time and mark2_value > min_time:
                    if self.marker_id == 1:
                        self.marker_id += 1
                        label_id = self.marker_id
                    elif self.marker_id == 2:
                        label_id = 2
                        self.remove_marker('second')
                    else:
                        self.marker_two_notice.setText('Marker1 not placed')
                    self.marker_two_notice.setText('')
                    self.marker_setpoint['Marker2'] = mark2_value
                    self.mark_two_time_value.setText(
                                            self.set_marker_two_value.text())
                    self.calculate_marker_stats()
                    self.calculate_signal_stats()
                    # Draw the marker
                    L =  self.ax.axvline(
                                    x=float(self.set_marker_two_value.text()), 
                                    linestyle='dashed', 
                                    color='red', 
                                    label='_Marker' + str(label_id))
                    self.fig.canvas.draw()
                else:
                    self.marker_two_notice.setText('Marker2 out of bounds')
            except:
                self.marker_two_notice.setText('Non-Valid value entered!')
    
    # Marker removal method
    def remove_marker(self, label):
        for item in self.ax.lines:
            if 'Marker' in item.get_label():
                self.marker_ind.append(item)

        # If there are two markers remove them from plot and adjust marker
        # time labels
        if label == 'both':
            self.marker_ind[0].remove()
            self.marker_ind[1].remove()
            self.marker_ind = []
            self.marker_setpoint['Marker1'] = 0
            self.marker_setpoint['Marker2'] = 0
            self.mark_one_time_value.setText('')
            self.mark_two_time_value.setText('')
            self.time_diff_value.setText('')
            self.marker_id = 0
        # Remove only marker1
        elif label == 'first':
            self.marker_ind[0].remove()
            self.marker_ind = []
            self.marker_setpoint['Marker1'] = 0
            self.mark_one_time_value.setText('')
            self.marker_id -= 1
        elif label == 'second':
            self.marker_ind[1].remove()
            self.marker_ind = []
            self.marker_setpoint['Marker2'] = 0
            self.mark_two_time_value.setText('')
            self.marker_id -= 1

        self.ax.set_xlabel('Time[s]')
        self.canvas.draw()
    
    # Method for plot removal
    def remove_plot(self, name):
        cnt = 0
        for item in self.ax.lines:
            if item.get_label() == name:
                self.ax.lines[cnt].remove()
            cnt += 1
        self.ax.relim()
        self.ax.autoscale_view()
        self.ax.legend(loc='upper right')
        self.ax.set_xlabel('Time[s]')
        self.canvas.draw()

        # Check if all elements are unticked
        counter = 0
        for i in range(self.list_widget.count()):
            if self.list_widget.item(i).checkState() == Qt.Checked:
                counter +=1
        if counter == 0:
            self.remove_marker('both')
            
    # On click event for plot, only two markers can be active at the time
    def on_click(self, event):
        try:
            # Catch left click event
            if event.button == 1:
                x = event.xdata
                if self.marker_id < 2:
                    if self.marker_id == 0:
                        self.marker_setpoint['Marker1'] = round(x)
                        self.mark_one_time_value.setText(
                                            str(self.marker_setpoint['Marker1']))
                        self.calculate_marker_stats()
                        self.calculate_signal_stats()
                    else:
                        self.marker_setpoint['Marker2'] = round(x)
                        self.mark_two_time_value.setText(
                                            str(self.marker_setpoint['Marker2']))
                        self.calculate_marker_stats()
                        self.calculate_signal_stats()
                    self.marker_id += 1
                    L =  self.ax.axvline(x=x, 
                                        linestyle='dashed', 
                                        color='red', 
                                        label='_Marker' + str(self.marker_id))
                    self.fig.canvas.draw()
            # Catch right click event
            elif event.button == 3:
                self.remove_marker('both')
        except TypeError:
            pass
    # Marker analysis method
    def calculate_marker_stats(self):
        if self.marker_setpoint['Marker2'] == 0:
            diff = self.data['Time'][-1] - self.marker_setpoint['Marker1']
            self.time_diff_value.setText(str(diff))
        else:
            diff = self.marker_setpoint['Marker2'] -  \
                   self.marker_setpoint['Marker1']
            
            self.time_diff_value.setText(convert_seconds(diff))
    # Signal analysis method
    def calculate_signal_stats(self):
        self.check_signals()
        selected_signal = ''
        signal_data = []
        num_off, num_on = 0, 0
        for item in self.signal_groupbox.children():
            try:
                if item.isChecked():
                    # Signal extraction block
                    selected_signal = item.text()
                    # If only one marker, Marker1 is placed on graph
                    if self.marker_setpoint['Marker2'] == 0 and self.marker_setpoint['Marker1'] != 0:
                        for i in range(len(self.data['Time'])):
                            if self.data['Time'][i] > self.marker_setpoint['Marker1']:
                                self.slice_index['ind1'] = i
                                break
                        signal_data = np.asarray(
                        self.data[selected_signal][self.slice_index['ind1']:], 
                                    dtype=np.float32)
                    # Both markers, Marker1 and Marker2 are present on graph
                    elif self.marker_setpoint['Marker1'] != 0 and self.marker_setpoint['Marker2'] != 0:
                        for i in range(len(self.data['Time'])):
                            if self.data['Time'][i] > self.marker_setpoint['Marker1']:
                                self.slice_index['ind1'] = i
                                break
                        for i in range(len(self.data['Time'])):
                            if self.data['Time'][len(self.data['Time']) - i - 1] < self.marker_setpoint['Marker2']:
                                self.slice_index['ind2'] = len(self.data['Time']) - i
                                break
                        signal_data = np.asarray(
                        self.data[selected_signal][self.slice_index['ind1']:self.slice_index['ind2'] - 1], 
                                                    dtype=np.float32)
                        
                    # No markers present, whole signal stats are showed
                    else:
                        signal_data = np.asarray(self.data[selected_signal], 
                                                    dtype=np.float32)
                    try:
                        # Signal mean calculation
                        self.mean_value.setText(str(np.mean(signal_data)))
                        # Standard deviation
                        self.std_value.setText(str(np.std(signal_data)))
                        # Maximum value
                        self.max_value.setText(str(np.max(signal_data)))
                        # Minimum value
                        self.min_value.setText(str(np.min(signal_data)))
                        # Max - Min
                        self.val_diff_value.setText(str(np.max(signal_data) - 
                                                    (np.min(signal_data))))
                        if np.max(signal_data) == 1.0:
                            for i in range(len(signal_data)):
                                if i != len(signal_data) - 1:
                                    temp = signal_data[i] - signal_data[i+1]
                                    if temp == 1:
                                        num_off += 1
                                    elif temp == -1:
                                        num_on += 1
                            self.on_off_value.setText(str(num_on) + 
                                                    '\\' + str(num_off))
                    except ValueError:
                        err_line1 = 'Missing data, result is empty array!'
                        err_line2 = '\n Please check snap file.' 
                        self.error_popup.showMessage(err_line1 + err_line2)
            except AttributeError:
                pass
Example #14
0
class Form(QWidget):
    """"""
    def __init__(
        self,
        parent: QApplication = None,
        *,
        title: str = "wooo",
        width: int = 400,
        height: int = 600,
    ) -> None:
        """Constructor"""
        super().__init__(parent)
        mixer.init()  # initializethe pygame mixer

        self.assets_path: str = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'assets')

        if parent is not None:
            self.parent = parent
        """
        self.parent.iconbitmap()
        """
        horiz_pos = 100  # from left of screen
        vertic_pos = 200  # from top of screen
        self.height = height
        self.width = width
        self.title = title

        self.setGeometry(horiz_pos, vertic_pos, self.width,
                         self.height)  # QtCore.QRect(x, y, w, h)
        self.setWindowTitle(self.title)

        self.setWindowIcon(QtGui.QIcon(self.assets_path + '/icons/melody.ico'))
        self.init_vol: int = 70
        self.paused: bool = False
        self.muted: bool = False
        self.playing: bool = False
        self.current_song: Opt[str] = None
        self.selected_song_num: Opt[int] = None
        self.playlist: List[str] = []

        self._init_ui()
        self.show()

    def _init_ui(self) -> None:
        self.layout = QVBoxLayout()
        self._menubar()

        self._create_rightframe()
        self._create_middleframe()
        self._create_leftframe()
        self._create_bottomframe()

        self.edit = QLineEdit("Write my name here")
        self.layout.addWidget(self.edit)

        self.greet_button = QPushButton("Show Greetings")
        self.greet_button.clicked.connect(self.greetings)
        self.layout.addWidget(self.greet_button)

        self._statusbar()
        self.setLayout(self.layout)

    def _menubar(self) -> None:
        menubar = QMenuBar()
        self.layout.addWidget(menubar)

        fileMenu = menubar.addMenu('File')
        fileMenu.addAction('Open', self.browse_file)
        fileMenu.addSeparator()
        fileMenu.addAction('Exit', self.close)

        helpMenu = menubar.addMenu('Help')
        helpMenu.addSeparator()
        helpMenu.addAction('About Us', self.about_us)
        # toolbar = self.addToolBar('Exit')
        # toolbar.addAction(self.play_music)

    def _statusbar(self) -> None:
        self.statusbar = QStatusBar()
        self.layout.addWidget(self.statusbar)
        self.statusbar.showMessage('Welcome', timeout=10_000)
        # status_bar = statusbar_parent.addPermanentWidget(statusbar_parent, stretch=True)

    def _create_rightframe(self) -> None:
        self.rightframe = QVBoxLayout()
        self.layout.addLayout(self.rightframe)

        self.filelabel = QLabel(text='Lets make some noise!')
        self.rightframe.addWidget(self.filelabel)

        self.lengthlabel = QLabel(text='Total Length : --:--')
        self.rightframe.addWidget(self.lengthlabel)

        self.currenttimelabel = QLabel(text='Current Time : --:--')
        self.rightframe.addWidget(self.currenttimelabel)

    def _create_leftframe(self) -> None:
        self.leftframe = QVBoxLayout()
        self.layout.addLayout(self.leftframe)

        self.playlistbox = QListWidget(self)
        self.playlistbox.setToolTip('''PlayListBox:
                                    Select song from list to play.
                                    Use browse or delete buttons to change playlist'''
                                    )
        self.leftframe.addWidget(self.playlistbox)

        self.browse_button = QPushButton("Browse")
        self.browse_button.clicked.connect(self.browse_file)
        self.leftframe.addWidget(self.browse_button)

        self.delete_button = QPushButton("Delete")
        self.delete_button.clicked.connect(self.del_song)
        self.leftframe.addWidget(self.delete_button)

    def _create_middleframe(self) -> None:
        self.middleframe = QVBoxLayout()
        self.layout.addLayout(self.middleframe)

        self.play_button = QPushButton("Play")
        self.play_button.clicked.connect(self.play_music)
        play_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/play.png'))
        # play_icon.addPixmap(QtGui.QPixmap(self.assets_path + '/icons/play.png'))
        self.play_button.setIcon(play_icon)
        # self.play_button.setIconSize(QtCore.QSize(100, 100))
        self.middleframe.addWidget(self.play_button)

        self.stop_button = QPushButton("Stop")
        self.stop_button.clicked.connect(self.stop_music)
        stop_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/stop.png'))
        self.stop_button.setIcon(stop_icon)
        # self.stop_button.setIconSize(QtCore.QSize(100, 100))
        self.middleframe.addWidget(self.stop_button)

        self.pause_button = QPushButton("Pause")
        self.pause_button.clicked.connect(self.pause_music)
        pause_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/pause.png'))
        self.pause_button.setIcon(pause_icon)
        # self.pause_button.setIconSize(QtCore.QSize(100, 100))
        self.middleframe.addWidget(self.pause_button)

    def _create_bottomframe(self) -> None:
        self.bottomframe = QVBoxLayout()
        self.layout.addLayout(self.bottomframe)

        self.volume_button = QPushButton("Mute")
        self.mute_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/mute.png'))
        self.volume_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/volume.png'))
        self.volume_button.setIcon(self.volume_icon)
        # self.volume_button.setIconSize(QtCore.QSize(100, 100))
        self.volume_button.clicked.connect(self.mute_music)
        self.bottomframe.addWidget(self.volume_button)

        self.rewind_button = QPushButton("Rewind")
        rewind_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/rewind.png'))
        self.rewind_button.setIcon(rewind_icon)
        # self.volume_button.setIconSize(QtCore.QSize(100, 100))
        self.play_button.clicked.connect(self.rewind_music)
        self.bottomframe.addWidget(self.rewind_button)

        self.vol_scale = QSlider(QtCore.Qt.Horizontal)
        self.vol_scale.setMinimum(0)
        self.vol_scale.setMaximum(100)
        # self.vol_scale.setTickPosition(QSlider.TicksBelow)
        # self.vol_scale.setTickInterval(5)
        self.vol_scale.setValue(self.init_vol)
        self.vol_scale.valueChanged.connect(self.set_vol)
        self.bottomframe.addWidget(self.vol_scale)
        mixer.music.set_volume(self.vol_scale.value())

        # exitAction = QtGui.QAction('Exit', self)
        # exitAction.setShortcut('Ctrl+Q')
        # exitAction.setStatusTip('Exit application')
        # exitAction.triggered.connect(self.close)

    def set_vol(self) -> None:
        self.vol_from_slider: int = self.vol_scale.value()
        volume_percent: float = self.vol_from_slider / 100
        mixer.music.set_volume(volume_percent)  # from 0 to 1

    def mute_music(self) -> None:
        if self.muted:  # Unmute the music
            mixer.music.set_volume(self.vol_pre_mute / 100)
            self.volume_button.setIcon(self.volume_icon)
            self.vol_scale.setValue(
                self.vol_pre_mute)  # (self.vol_from_slider)
            self.muted = False
        else:  # mute the music
            self.vol_pre_mute: int = self.vol_scale.value()
            mixer.music.set_volume(0)
            self.volume_button.setIcon(self.mute_icon)
            self.vol_scale.setValue(0)
            self.muted = True

    def greetings(self) -> None:
        text = self.edit.text()
        print('Contents of QLineEdit widget: {}'.format(text))
        self.statusbar.showMessage(text, timeout=2_000)

    def about_us(self) -> None:
        text = self.edit.text()
        print('Contents of QLineEdit widget: {}'.format(text))

    def browse_file(self) -> None:
        get_filename_path: Tuple[str, str] = QFileDialog.getOpenFileName(
            self,  # if cancelled, returns ("", "")
            "Open Sound File",
            self.assets_path,
            "Sound Files (*.wav *.mp3 *.ogg)")
        print(get_filename_path)
        filename_path = get_filename_path[0]
        if filename_path:
            self.add_to_playlist(filename_path)
            mixer.music.queue(filename_path)

    def add_to_playlist(self, filepath: str) -> None:
        filename = os.path.basename(filepath)
        index = 0
        # print(self.playlist)
        # QListWidgetItem(self.playlistbox).setText(filename)  # last_added =
        self.playlistbox.insertItem(index, filename)  # .addItems([filenames])
        self.playlist.insert(index, filepath)
        index += 1

    def del_song(self) -> None:
        self.get_selected_song_num()  # update self.selected_song_num
        if self.selected_song_num is not None:  # if a song is selected
            print(self.selected_song_num)
            if self.playlist[
                    self.
                    selected_song_num] == self.current_song:  # if song is currently playing
                self.stop_music()  # stop it
            self.playlistbox.takeItem(
                self.selected_song_num
            )  # remove the song from the box, note returns the song object
            self.playlist.pop(self.selected_song_num)  # and playlist
            # self.selected_song_num remains same, so will play/del next song?
            self.reset_song()
            self.statusbar.showMessage("Song removed from playlist",
                                       timeout=1_000)
            self.selected_song_num = None  # reset self.selected_song_num"""

    def get_selected_song_num(self) -> None:
        if self.playlistbox.count() > 0:
            selected_song_from_box = self.playlistbox.currentItem(
            )  # get current item
            if selected_song_from_box:
                self.selected_song: str = selected_song_from_box.text(
                )  # get items text
                self.selected_song_num = self.playlistbox.currentRow()
            else:
                self.statusbar.showMessage("Choose a file from the playlist",
                                           timeout=2_000)
        else:
            self.statusbar.showMessage("No files loaded to playlist",
                                       timeout=2_000)

    def stop_music(self) -> None:
        if self.playing:
            self.playing = False
            self.current_song = None
            mixer.music.stop()
            self.statusbar.showMessage("Music Stopped", timeout=5_000)

    def pause_music(self) -> None:
        if self.playing:
            self.paused = True
            mixer.music.pause()
            self.statusbar.showMessage("Music paused", timeout=0)

    def rewind_music(self) -> None:
        if self.playing:
            self.stop_music()
            time.sleep(0.5)
            self.play_music()
            self.statusbar.showMessage("Music Rewound to start", timeout=1_000)

    def reset_song(self) -> None:
        self.current_song = None
        self.filelabel.setText("")
        self.lengthlabel.setText('Total Length : --:00')
        self.currenttimelabel.setText("Current Time : --:--")
        # self.statusbar.showMessage("", timeout=0)

    def show_details(self, play_song: str) -> None:
        self.filelabel.setText("Playing" + ' - ' + os.path.basename(play_song))
        file_data = os.path.splitext(play_song)

        if file_data[1] == '.mp3':
            audio = MP3(play_song)
            total_length = audio.info.length
        elif file_data[1] == '.wav':
            a = mixer.Sound(play_song)
            total_length = a.get_length()
        else:
            try:
                a = mixer.Sound(play_song)
                total_length = a.get_length()
            except Exception as e:
                print(e)
        self.current_song_lenth = total_length
        mins, secs = divmod(total_length, 60)  # returns (time//60, remainder)
        mins = round(mins)
        secs = round(secs)
        timeformat = '{:02d}:{:02d}'.format(mins, secs)
        self.lengthlabel.setText("Total Length" + ' - ' + timeformat)

        self.t1 = threading.Thread(target=self.start_count,
                                   args=(total_length, ))
        self.t1.start()

    def start_count(self, total_time: int) -> None:
        """"""
        current_time = 0
        while current_time <= total_time and mixer.music.get_busy(
        ):  # music.get_busy() -> Returns False when stopped
            if self.paused:
                continue  # if paused, infinite loop (don't count)
            else:
                mins, secs = divmod(current_time, 60)
                mins = round(mins)
                secs = round(secs)
                timeformat = '{:02d}:{:02d}'.format(mins, secs)
                self.currenttimelabel.setText("Current Time" + ' - ' +
                                              timeformat)
                time.sleep(1)
                current_time += 1

    def play_music(self) -> None:
        '''if not playing: play, if playing and paused, unpause'''
        self.get_selected_song_num()  # update self.selected_song_num
        if self.selected_song_num is not None and self.playlist:
            play_it: Opt[str] = self.playlist[self.selected_song_num]
        else:
            play_it = None

        if not self.playing and play_it:  # if not yet playing, play selected song
            try:
                self.stop_music()
                time.sleep(0.5)
                mixer.music.load(play_it)
                mixer.music.play()
            except Exception as e:
                # messagebox.showerror('File not found, or unknown file type. Please check again.')
                if DEBUG: print(e)
            else:
                self.playing = True
                self.current_song = play_it
                self.show_details(play_it)
                self.statusbar.showMessage("Playing music" + ' - ' +
                                           os.path.basename(play_it))
        elif self.playing and self.paused:  # if paused, resume
            mixer.music.unpause()
            # self.statusbar.showMessage("Playing music" + ' - ' + os.path.basename(play_it))
            self.statusbar.showMessage("Music Resumed", timeout=1_000)
            self.paused = False
        elif self.playing and not self.paused:
            if play_it == self.current_song and play_it is not None:  # if already playing song, do nothing
                self.statusbar.showMessage(
                    "Playing music" + ' - ' + os.path.basename(play_it),
                    timeout=0)  # TODO timout current song len
            else:  # if different song selected, retry
                self.playing = False
                self.play_music()

    def close(self) -> None:
        try:
            self.stop_music()
            QApplication.closeAllWindows()
        except Exception as e:
            sys.exit(1)
            if DEBUG: print(e)
        else:
            print('App closed')
Example #15
0
class PiecesPlayer(QWidget):
    """ main widget of application (used as widget inside PiecesMainWindow) """
    def __init__(self, parent):
        """ standard constructor: set up class variables, ui elements
            and layout """

        # TODO: split current piece info into separate lineedits for title, album name and length
        # TODO: make time changeable by clicking next to the slider (not only
        #       by dragging the slider)
        # TODO: add "about" action to open info dialog in new "help" menu
        # TODO: add option to loop current piece (?)
        # TODO: more documentation
        # TODO: add some "whole piece time remaining" indicator? (complicated)
        # TODO: implement a playlist of pieces that can be edited and enable
        #       going back to the previous piece (also un- and re-shuffling?)
        # TODO: implement debug dialog as menu action (if needed)

        if not isinstance(parent, PiecesMainWindow):
            raise ValueError('Parent widget must be a PiecesMainWindow')

        super(PiecesPlayer, self).__init__(parent=parent)

        # -- declare and setup variables for storing information --
        # various data
        self._set_str = ''  # string of currently loaded directory sets
        self._pieces = {}  # {<piece1>: [<files piece1 consists of>], ...}
        self._playlist = []  # list of keys of self._pieces (determines order)
        self._shuffled = True  # needed for (maybe) reshuffling when looping
        # doc for self._history:
        # key: timestamp ('HH:MM:SS'),
        # value: info_str of piece that started playing at that time
        self._history = {}
        self._status = 'Paused'
        self._current_piece = {'title': '', 'files': [], 'play_next': 0}
        self._default_volume = 60  # in percent from 0 - 100
        self._volume_before_muted = self._default_volume
        # set to true by self.__event_movement_ended and used by self.__update
        self._skip_to_next = False
        # vlc-related variables
        self._vlc_instance = VLCInstance()
        self._vlc_mediaplayer = self._vlc_instance.media_player_new()
        self._vlc_mediaplayer.audio_set_volume(self._default_volume)
        self._vlc_medium = None
        self._vlc_events = self._vlc_mediaplayer.event_manager()

        # -- create and setup ui elements --
        # buttons
        self._btn_play_pause = QPushButton(QIcon(get_icon_path('play')), '')
        self._btn_previous = QPushButton(QIcon(get_icon_path('previous')), '')
        self._btn_next = QPushButton(QIcon(get_icon_path('next')), '')
        self._btn_volume = QPushButton(QIcon(get_icon_path('volume-high')), '')
        self._btn_loop = QPushButton(QIcon(get_icon_path('loop')), '')
        self._btn_loop.setCheckable(True)
        self._btn_play_pause.clicked.connect(self.__action_play_pause)
        self._btn_previous.clicked.connect(self.__action_previous)
        self._btn_next.clicked.connect(self.__action_next)
        self._btn_volume.clicked.connect(self.__action_volume_clicked)
        # labels
        self._lbl_current_piece = QLabel('Current piece:')
        self._lbl_movements = QLabel('Movements:')
        self._lbl_time_played = QLabel('00:00')
        self._lbl_time_left = QLabel('-00:00')
        self._lbl_volume = QLabel('100%')
        # needed so that everything has the same position
        # independent of the number of digits of volume
        self._lbl_volume.setMinimumWidth(55)
        # sliders
        self._slider_time = QSlider(Qt.Horizontal)
        self._slider_volume = QSlider(Qt.Horizontal)
        self._slider_time.sliderReleased.connect(
            self.__event_time_changed_by_user)
        self._slider_volume.valueChanged.connect(self.__event_volume_changed)
        self._slider_time.setRange(0, 100)
        self._slider_volume.setRange(0, 100)
        self._slider_volume.setValue(self._default_volume)
        self._slider_volume.setMinimumWidth(100)
        # other elements
        self._checkbox_loop_playlist = QCheckBox('Loop playlist')
        self._lineedit_current_piece = QLineEdit()
        self._lineedit_current_piece.setReadOnly(True)
        self._lineedit_current_piece.textChanged.connect(
            self.__event_piece_text_changed)
        self._listwidget_movements = QListWidget()
        self._listwidget_movements.itemClicked.connect(
            self.__event_movement_selected)

        # -- create layout and insert ui elements--
        self._layout = QVBoxLayout(self)
        # row 0 (name of current piece)
        self._layout_piece_name = QHBoxLayout()
        self._layout_piece_name.addWidget(self._lbl_current_piece)
        self._layout_piece_name.addWidget(self._lineedit_current_piece)
        self._layout.addLayout(self._layout_piece_name)
        # rows 1 - 5 (movements of current piece)
        self._layout.addWidget(self._lbl_movements)
        self._layout.addWidget(self._listwidget_movements)
        # row 6 (time)
        self._layout_time = QHBoxLayout()
        self._layout_time.addWidget(self._lbl_time_played)
        self._layout_time.addWidget(self._slider_time)
        self._layout_time.addWidget(self._lbl_time_left)
        self._layout.addLayout(self._layout_time)
        # row 7 (buttons and volume)
        self._layout_buttons_and_volume = QHBoxLayout()
        self._layout_buttons_and_volume.addWidget(self._btn_play_pause)
        self._layout_buttons_and_volume.addWidget(self._btn_previous)
        self._layout_buttons_and_volume.addWidget(self._btn_next)
        self._layout_buttons_and_volume.addWidget(self._btn_loop)
        self._layout_buttons_and_volume.addSpacing(40)
        # distance between loop and volume buttons: min. 40, but stretchable
        self._layout_buttons_and_volume.addStretch()
        self._layout_buttons_and_volume.addWidget(self._btn_volume)
        self._layout_buttons_and_volume.addWidget(self._slider_volume)
        self._layout_buttons_and_volume.addWidget(self._lbl_volume)
        self._layout.addLayout(self._layout_buttons_and_volume)

        # -- setup hotkeys --
        self._KEY_CODES_PLAY_PAUSE = [269025044]
        self._KEY_CODES_NEXT = [269025047]
        self._KEY_CODES_PREVIOUS = [269025046]
        self._keyboard_listener = keyboard.Listener(on_press=self.__on_press)
        self._keyboard_listener.start()
        QShortcut(QKeySequence('Space'), self, self.__action_play_pause)

        # -- various setup --
        self._timer = QTimer(self)
        self._timer.timeout.connect(self.__update)
        self._timer.start(100)  # update every 100ms
        self.setMinimumWidth(900)
        self.setMinimumHeight(400)
        # get directory set(s) input and set up self._pieces
        # (exec_ means we'll wait for the user input before continuing)
        DirectorySetChooseDialog(self, self.set_pieces_and_playlist).exec_()
        # skip to next movement / next piece when current one has ended
        self._vlc_events.event_attach(VLCEventType.MediaPlayerEndReached,
                                      self.__event_movement_ended)

    def __action_next(self):
        """ switches to next file in self._current_piece['files']
            or to the next piece, if the current piece has ended """

        reset_pause_after_current = False

        # current movement is last of the current piece
        if self._current_piece['play_next'] == -1:
            if len(self._playlist) == 0:  # reached end of playlist
                if self._btn_loop.isChecked():
                    self._playlist = list(self._pieces.keys())
                    if self._shuffled:
                        shuffle(self._playlist)
                    return

                if self._status == 'Playing':
                    self.__action_play_pause()
                self._current_piece['title'] = ''
                self._current_piece['files'] = []
                self._current_piece['play_next'] = -1
                self._lineedit_current_piece.setText('')
                self.__update_movement_list()
                self.parentWidget().update_status_bar(
                    self._status, 'End of playlist reached.')
                return
            else:
                if self.parentWidget().get_exit_after_current():
                    self.parentWidget().exit()
                if self.parentWidget().get_pause_after_current():
                    self.__action_play_pause()
                    reset_pause_after_current = True
                    # reset of the menu action will be at the end of this
                    # function, or else we won't stay paused

                self._current_piece['title'] = self._playlist.pop(0)
                self._current_piece['files'] = [
                    p[1:-1] for p in self._pieces[self._current_piece['title']]
                ]
                # some pieces only have one movement
                self._current_piece['play_next'] = \
                    1 if len(self._current_piece['files']) > 1 else -1
                self.__update_vlc_medium(0)
                self._lineedit_current_piece.setText(
                    create_info_str(self._current_piece['title'],
                                    self._current_piece['files']))
                self.__update_movement_list()
                self._history[datetime.now().strftime('%H:%M:%S')] = \
                    self._lineedit_current_piece.text()
        else:
            self.__update_vlc_medium(self._current_piece['play_next'])
            # next is last movement
            if self._current_piece['play_next'] == \
               len(self._current_piece['files']) - 1:
                self._current_piece['play_next'] = -1
            else:  # there are at least two movements of current piece left
                self._current_piece['play_next'] += 1
        if self._status == 'Paused' and not reset_pause_after_current:
            self.__action_play_pause()
        elif reset_pause_after_current:
            self.parentWidget().set_pause_after_current(False)
        else:
            self._vlc_mediaplayer.play()
        self.parentWidget().update_status_bar(
            self._status,
            f'{len(self._pieces) - len(self._playlist)}/{len(self._pieces)}')

    def __action_play_pause(self):
        """ (gets called when self._btn_play_pause is clicked)
            toggles playing/pausing music and updates everything as needed """

        # don't do anything now (maybe end of playlist reached?)
        if self._current_piece['title'] == '':
            return

        if self._status == 'Paused':
            if not self._vlc_medium:
                self.__action_next()
            self._vlc_mediaplayer.play()
            self._btn_play_pause.setIcon(QIcon(get_icon_path('pause')))
            self._status = 'Playing'
        else:
            self._vlc_mediaplayer.pause()
            self._btn_play_pause.setIcon(QIcon(get_icon_path('play')))
            self._status = 'Paused'
        self.parentWidget().update_status_bar(
            self._status,
            f'{len(self._pieces) - len(self._playlist)}/{len(self._pieces)}')

    def __action_previous(self):
        """ (called when self._btn_previous ist clicked)
            goes back one movement of the current piece, if possible
            (cannot go back to previous piece) """

        # can't go back to previous piece, but current one has no or one movement
        if len(self._current_piece['files']) <= 1:
            pass
        # currently playing first movement, so nothing to do as well
        elif self._current_piece['play_next'] == 1:
            pass
        else:  # we can go back one movement
            # currently at last movement
            if self._current_piece['play_next'] == -1:
                # set play_next to last movement
                self._current_piece['play_next'] = \
                    len(self._current_piece['files']) - 1
            else:  # currently before last movement
                # set play_next to current movement
                self._current_piece['play_next'] -= 1
            self._vlc_mediaplayer.stop()
            self.__update_vlc_medium(self._current_piece['play_next'] - 1)
            self._vlc_mediaplayer.play()

    def __action_volume_clicked(self):
        """ (called when self._btn_volume is clicked)
            (un)mutes volume """

        if self._slider_volume.value() == 0:  # unmute volume
            self._slider_volume.setValue(self._volume_before_muted)
        else:  # mute volume
            self._volume_before_muted = self._slider_volume.value()
            self._slider_volume.setValue(0)

    def __event_movement_ended(self, event):
        """ (called when self._vlc_media_player emits a MediaPlayerEndReached
            event)
            sets self._skip_to_next to True so the next self.__update call
            will trigger self.__action_next """

        self._skip_to_next = True

    def __event_movement_selected(self):
        """ (called when self._listwidget_movements emits itemClicked)
            skips to the newly selected movement """

        index = self._listwidget_movements.indexFromItem(
            self._listwidget_movements.currentItem()).row()
        # user selected a movement different from the current one
        if index != self.__get_current_movement_index():
            self._current_piece['play_next'] = index
            self.__action_next()

    def __event_piece_text_changed(self):
        """ (called when self._lineedit_current_piece emits textChanged)
            ensures that the user sees the beginning of the text in
            self._lineedit_current_piece (if text is too long, the end will be
            cut off and the user must scroll manually to see it) """

        self._lineedit_current_piece.setCursorPosition(0)

    def __event_volume_changed(self):
        """ (called when value of self._slider_volume changes)
            updates text of self._lbl_volume to new value of self._slider_value
            and sets icon of self._btn_volume to a fitting one """

        volume = self._slider_volume.value()
        self._lbl_volume.setText(f'{volume}%')
        if volume == 0:
            self._btn_volume.setIcon(QIcon(get_icon_path('volume-muted')))
        elif volume < 34:
            self._btn_volume.setIcon(QIcon(get_icon_path('volume-low')))
        elif volume < 67:
            self._btn_volume.setIcon(QIcon(get_icon_path('volume-medium')))
        else:
            self._btn_volume.setIcon(QIcon(get_icon_path('volume-high')))
        self._vlc_mediaplayer.audio_set_volume(volume)

    def __event_time_changed_by_user(self):
        """ (called when user releases self._slider_time)
            synchronizes self._vlc_mediaplayer's position to the new value
            of self._slider_time """

        self._vlc_mediaplayer.set_position(self._slider_time.value() / 100)

    def __get_current_movement_index(self):
        """ returns the index of the current movement in
            self._current_piece['files'] """

        play_next = self._current_piece['play_next']
        if play_next == -1:
            return len(self._current_piece['files']) - 1
        else:
            return play_next - 1

    def __on_press(self, key):
        """ (called by self._keyboard_listener when a key is pressed)
            looks up key code corresponding to key and calls the appropriate
            action function """

        try:  # key is not always of the same type (why would it be?!)
            key_code = key.vk
        except AttributeError:
            key_code = key.value.vk
        if key_code in self._KEY_CODES_PLAY_PAUSE:
            self.__action_play_pause()
        elif key_code in self._KEY_CODES_NEXT:
            self.__action_next()
        elif key_code in self._KEY_CODES_PREVIOUS:
            self.__action_previous()

    def __update_movement_list(self):
        """ removes all items currently in self._listwidget_movements and adds
            everything in self._current_piece['files] """

        # TODO: use ID3 title instead of filename

        while self._listwidget_movements.count() > 0:
            self._listwidget_movements.takeItem(0)
        files = self._current_piece['files']
        if os_name == 'nt':  # windows paths look different than posix paths
            # remove path to file, title number and .mp3 ending
            files = [i[i.rfind('\\') + 3:-4] for i in files]
        else:
            files = [i[i.rfind('/') + 4:-4] for i in files]
        self._listwidget_movements.addItems(files)

    def __update(self):
        """ (periodically called when self._timer emits timeout signal)
            updates various ui elements"""

        # -- select currently playing movement in self._listwidget_movements --
        if self._listwidget_movements.count() > 0:
            self._listwidget_movements.item(
                self.__get_current_movement_index()).setSelected(True)

        # -- update text of self._lbl_time_played and self._lbl_time_left,
        # if necessary --
        if self._vlc_medium:
            try:
                time_played = self._vlc_mediaplayer.get_time()
                medium_duration = self._vlc_medium.get_duration()
                # other values don't make sense (but do occur)
                if (time_played >= 0) and (time_played <= medium_duration):
                    self._lbl_time_played.setText(
                        get_time_str_from_ms(time_played))
                else:
                    self._lbl_time_played.setText(get_time_str_from_ms(0))
                self._lbl_time_left.setText(
                    f'-{get_time_str_from_ms(medium_duration - time_played)}')
            except OSError:  # don't know why that occurs sometimes
                pass

        # -- update value of self._slider_time --
        # don't reset slider to current position if user is dragging it
        if not self._slider_time.isSliderDown():
            try:
                self._slider_time.setValue(
                    self._vlc_mediaplayer.get_position() * 100)
            except OSError:  # don't know why that occurs sometimes
                pass

        if self._skip_to_next:
            self._skip_to_next = False
            self.__action_next()

    def __update_vlc_medium(self, files_index):
        old_medium = self._vlc_medium
        self._vlc_medium = self._vlc_instance.media_new(
            self._current_piece['files'][files_index])
        self._vlc_medium.parse()
        self._vlc_mediaplayer.set_media(self._vlc_medium)
        if old_medium:  # only release if not None
            old_medium.release()

    def get_history(self):
        """ getter function for parent widget """

        return self._history

    def get_set_str(self):
        """ getter function for parent widget """

        return self._set_str if self._set_str != '' \
            else 'No directory set loaded.'

    def set_pieces_and_playlist(self, pieces, playlist, set_str, shuffled):
        """ needed so that DirectorySetChooseDialog can set our self._pieces
            and self._playlist """

        # just to be sure
        if isinstance(pieces, dict) and isinstance(playlist, list):
            self._vlc_mediaplayer.stop()
            self._set_str = set_str
            self._pieces = pieces
            self._playlist = playlist
            self._shuffled = shuffled
            self._current_piece['title'] = self._playlist.pop(0)
            self._current_piece['files'] = [
                p.replace('"', '')
                for p in self._pieces[self._current_piece['title']]
            ]
            self._current_piece['play_next'] = \
                1 if len(self._current_piece['files']) > 1 else -1
            self._lineedit_current_piece.setText(
                create_info_str(self._current_piece['title'],
                                self._current_piece['files']))
            self.__update_movement_list()
            self.__update_vlc_medium(0)
            self._history[datetime.now().strftime('%H:%M:%S')] = \
                self._lineedit_current_piece.text()

    def exit(self):
        """ exits cleanly """

        try:  # don't know why that occurs sometimes
            self._vlc_mediaplayer.stop()
            self._vlc_mediaplayer.release()
            self._vlc_instance.release()
        except OSError:
            pass

        self._keyboard_listener.stop()
Example #16
0
class ClientWindow(QDialog):

    def __init__(self):
        super(ClientWindow, self).__init__()

        self.resize(823,511)
        self.setWindowTitle('用户客户端')
        self.friendList = QListWidget()
        self.friendList.doubleClicked.connect(self.changeFriendText)
        self.friendList.clicked.connect(self.changeFriendText)
        self.portLine = QLineEdit()
        self.portLine.setText('12345')
        self.connectBtn = QPushButton('连接')
        self.connectBtn.clicked.connect(self.setupFun)
        self.messageText = QTextEdit()
        self.messageLine = QLineEdit()
        self.sendBtn = QPushButton('发送')
        self.sendBtn.clicked.connect(self.sendFun)

        self.text = ''
        self.userText = {}

        self.initUI()
        self.palette = QPalette()
        self.palette.setBrush(QPalette.Background, QBrush(QPixmap('./image/background.jpg')))
        self.setPalette(self.palette)
        self.client = Client()
        self.client.trigger.connect(self.updateTextFun)
        self.ininData()

    def changeFriendText(self):
        currentItem = self.friendList.currentItem().text()
        self.text = self.userText[currentItem]
        self.messageText.setText(self.text)

    def ininData(self):
        self.friendList.addItem('broadcast')
        self.userText['broadcast'] = ''
        self.friendList.setCurrentItem(self.friendList.item(0))

    def initUI(self):

        mainLayout = QVBoxLayout()
        mainWidget = QWidget()

        widget1 = QWidget()
        layout1 = QHBoxLayout()
        layout1.addWidget(self.portLine)
        layout1.addWidget(self.connectBtn)
        widget1.setLayout(layout1)
        mainLayout.addWidget(widget1)

        widget2 = QWidget()
        layout2 = QHBoxLayout()
        layout2.addWidget(self.messageText)
        layout2.addWidget(self.friendList)
        layout2.setStretch(0,2)
        layout2.setStretch(0,1)
        widget2.setLayout(layout2)
        mainLayout.addWidget(widget2)

        # mainLayout.addStretch(1)
        widget3 = QWidget()
        layout3 = QHBoxLayout()
        layout3.addWidget(self.messageLine)
        layout3.addWidget(self.sendBtn)
        widget3.setLayout(layout3)
        mainLayout.addWidget(widget3)

        self.setLayout(mainLayout)

    def setupFun(self):
        port = int(self.portLine.text())
        self.client.setupFun(port)
        self.client.start()

    def sendFun(self):
        addr = self.friendList.currentItem().text()
        message = self.messageLine.text()
        if message != 'add' and message != 'del':
            self.userText[addr] += '我:' + message + '\n'
        self.changeFriendText()
        if addr != 'broadcast':
            addr = ('localhost',int(addr))
        self.client.sendFun(message,addr)
        self.messageLine.setText('')


    def updateTextFun(self,data):

        currentItem = self.friendList.currentItem().text()
        data = json.loads(data)
        if 'cmd' in data.keys():
            if data['cmd'] == 'add':
                fromUser = str(data['from'])
                addr = ('127.0.0.1',int(fromUser))
                item = self.friendList.findItems(fromUser,Qt.MatchExactly)
                if fromUser not in self.userText.keys():
                    self.userText[fromUser] = ''
                if len(item) == 0:
                    self.friendList.addItem(fromUser)
                    self.client.sendFun('add',addr)  # 已添加
            elif data['cmd'] == 'del':
                fromUser = str(data['from'])
                rows = self.friendList.count()
                for row in range(rows):
                    if fromUser == self.friendList.item(row).text():
                        self.friendList.takeItem(row)
        else:
            message = data['message']
            fromUser = str(data['from'])
            if fromUser != 'broadcast':
                addr = ('127.0.0.1', int(fromUser))
                item = self.friendList.findItems(fromUser, Qt.MatchExactly)
                if fromUser not in self.userText.keys():
                    self.userText[fromUser] = ''
                if len(item) == 0:
                    self.friendList.addItem(fromUser)
                    self.client.sendFun('add', addr)  # 已添加
            if message != 'add' and message != 'del':
                self.userText[fromUser] += fromUser + ':' + message + '\n'
                if fromUser == currentItem:
                    self.text = self.userText[fromUser]
                    self.messageText.setText(self.text)


    def closeEvent(self, event:PySide2.QtGui.QCloseEvent):
        self.client.closeFun()
Example #17
0
class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()

        self.lastProjectDirectory = None
        self.view = None
        self.items = dict()

        self.loadSettings()

        self.setWindowTitle("2D Tagger")
        self.createActions()
        self.createMenus()
        self.createFileList()
        self.createContainer()
        self.createStatusBar()

    def loadSettings(self):
        try:
            with io.open(Path(__file__).parent / 'app.json', 'r') as f:
                data = json.load(f)
                if 'lastProjectDirectory' in data:
                    self.lastProjectDirectory = data['lastProjectDirectory']
        except:
            pass

    def saveSettings(self):
        data = dict()
        data['lastProjectDirectory'] = self.lastProjectDirectory
        with io.open(Path(__file__).parent / 'app.json', 'w') as f:
            json.dump(data, f, indent=' ')

    def createActions(self):
        # root = QFileInfo(__file__).absolutePath()
        self.openAct = QAction(
            # QIcon(root + '/icons/open.png'),
            "&Open",
            self,
            shortcut=QKeySequence.Open,
            statusTip="Open project",
            triggered=self.openProject)
        self.closeAct = QAction(
            # QIcon(root + '/icons/close.png'),
            "&Close",
            self,
            shortcut=QKeySequence.Close,
            statusTip="Close project",
            triggered=self.closeProject,
            enabled=False)
        self.exitAct = QAction(
            # QIcon(root + '/icons/quit.png'),
            "&Quit",
            self,
            shortcut=QKeySequence.Quit,
            statusTip="Close the application",
            triggered=self.close)
        self.aboutAct = QAction("&About",
                                self,
                                statusTip="Show the application's About box",
                                triggered=self.about)

    def createMenus(self):
        fileMenu = self.menuBar().addMenu("&File")
        fileMenu.addAction(self.openAct)
        fileMenu.addAction(self.closeAct)
        fileMenu.addSeparator()
        fileMenu.addAction(self.exitAct)

        self.menuBar().addSeparator()
        helpMenu = self.menuBar().addMenu("&Help")
        helpMenu.addAction(self.aboutAct)

    def createFileList(self):
        self.files = QListWidget()
        self.files.setSelectionMode(QAbstractItemView.SingleSelection)
        self.files.setSortingEnabled(False)
        self.files.itemSelectionChanged.connect(self.onSelect)
        self.files.itemDoubleClicked.connect(self.onToggle)
        self.files.setEnabled(False)

        dock = QDockWidget("Images", self)
        dock.setAllowedAreas(Qt.LeftDockWidgetArea)
        dock.setFixedWidth(320)
        dock.setFeatures(QDockWidget.NoDockWidgetFeatures)
        dock.setWidget(self.files)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock)

    def createContainer(self):
        self.container = QWidget(self)
        self.container.setStyleSheet("View { background: black; }")
        self.container.setLayout(QVBoxLayout())
        self.setCentralWidget(self.container)

    def createStatusBar(self):
        self.statusBar().showMessage("Initialized")

    def enableProjectActions(self, enabled):
        actions = [self.closeAct, self.files]
        for action in actions:
            action.setEnabled(enabled)

    def closeEvent(self, event):
        event.accept()

    def openProject(self, path=None):
        if not path:
            path = QFileDialog.getExistingDirectory(
                self, "Choose image directory", dir=self.lastProjectDirectory)
        if path:
            self.closeProject()

            self.view = View(self)
            self.view.previous.connect(self.onPrevious)
            self.view.next.connect(self.onNext)
            self.container.layout().addWidget(self.view)

            filename = Path(path) / "items.json"
            if filename.exists():
                with io.open(filename, 'r') as f:
                    self.items = json.load(f)
            else:
                self.items = dict()
            for filename in find_images(Path(path)):
                if filename in self.items:
                    continue
                self.items[filename] = dict({"active": True})

            self.refreshItems()
            self.files.setItemSelected(self.files.item(0), True)

            self.enableProjectActions(True)

            self.lastProjectDirectory = path
            self.saveProject()
            self.saveSettings()

    def saveProject(self):
        if not self.view:
            return
        with io.open(Path(self.lastProjectDirectory) / "items.json", 'w') as f:
            json.dump(self.items, f, indent='  ')

    def closeProject(self):
        self.enableProjectActions(False)
        if self.view:
            self.container.layout().removeWidget(self.view)
            self.view.close()
            self.view = None
        self.items = dict()
        self.refreshItems()

    def selection(self):
        selection = self.files.selectedItems()
        if len(selection) > 0:
            return selection[0].text()
        return None

    def refreshItems(self):
        filenames = sorted(self.items.keys())
        for i in range(len(filenames)):
            filename = filenames[i]
            item = self.items[filename]
            file = self.files.item(i)
            if not file:
                file = QListWidgetItem(filenames[i])
                self.files.insertItem(i, file)
            if item['active']:
                file.setTextColor(QColor.fromRgbF(0.0, 0.5, 0.0))
            else:
                file.setTextColor(QColor.fromRgbF(0.5, 0.0, 0.0))
        while self.files.count() > len(filenames):
            self.files.takeItem(len(filenames))

    @Slot()
    def onToggle(self, item):
        self.items[
            item.text()]['active'] = not self.items[item.text()]['active']
        self.refreshItems()
        self.saveProject()

    @Slot()
    def onSelect(self):
        selection = self.selection()
        if self.view:
            self.view.save()
            if selection:
                self.view.load(Path(self.lastProjectDirectory) / selection)

    @Slot()
    def onPrevious(self):
        if self.files.count() == 0:
            return
        index = 0
        selection = self.selection()
        if selection:
            for i in range(self.files.count()):
                item = self.files.item(i)
                if item.text() == selection:
                    index = i - 1
                    break
        if index < 0:
            index = self.files.count() - 1
        self.files.setItemSelected(self.files.item(index), True)

    @Slot()
    def onNext(self):
        if self.files.count() == 0:
            return
        index = 0
        selection = self.selection()
        if selection:
            for i in range(self.files.count()):
                item = self.files.item(i)
                if item.text() == selection:
                    index = i + 1
                    break
        if index >= self.files.count():
            index = 0
        self.files.setItemSelected(self.files.item(index), True)

    @Slot(str)
    def showMessage(self, message):
        self.statusBar().showMessage(message)

    def about(self):
        QMessageBox.about(
            self, "About Application",
            "The <b>2D Tagger</b> can load images, manually tag/label images and export result."
        )
Example #18
0
class EventViewer(QDialog):
    def __init__(self, alid=0, db=0, mode=0):
        super().__init__()
        self.font = mainfont
        self.resize(1000, 600)
        layout = QGridLayout()
        self.layout = layout
        self.buttext = []
        self.dictViewer = QWidget()

        self.linedits = {}
        self.last_eid = 0
        self.photo_ids = 0
        self.QLABELM_TYPE = type(QLabelM())

        self.listWidget = QListWidget()
        self.listWidget.itemDoubleClicked.connect(self.doubleClick)
        self.listWidget.itemSelectionChanged.connect(self.itemChanged)

        self.setFont(mainfont)
        self.db = db
        self.alid = alid
        self.event_ids = db.get_all_event_ids(self.alid)
        self.photo_gallery = QLabel()
        #self.photo_gallery.setAlignment(Qt.AlignCenter)
        #self.photo_gallery.setPixmap(QPixmap('f.png').scaled(400,400,Qt.KeepAspectRatio))
        print(self.event_ids)
        if self.event_ids:
            for eid in self.event_ids:
                event = db.get_event_data(self.alid, eid)
                print(event)
                if event:
                    text = ''
                    text = event['event_head'] if type(event) == type(
                        {}) and 'event_head' in event.keys(
                        ) and event['event_head'] != '' else text
                    item = QListWidgetItem(text)
                    if type(event) == type({}) and 'eid' in event.keys():
                        item.setWhatsThis(str(event['eid']))
                    self.listWidget.addItem(item)
            if self.listWidget.count():
                self.listWidget.setCurrentRow(0)

        self.mode = mode

        def openMenu(position):
            # Создание PopupMenu
            menu = QMenu()
            if mode > 0:
                addAction = menu.addAction('Добавить событие')
                #menu.addSeparator()
                editAction = menu.addAction('Переименовать событие')
                #menu.addSeparator()
                delAction = menu.addAction('Удалить событие')
                delAllAction = menu.addAction('Удалить все события')
                menu.addSeparator()
            else:
                addAction, editAction, delAction, delAllAction = QAction(
                ), QAction(), QAction(), QAction()
            quitAction = menu.addAction('Выход')
            action = menu.exec_(self.mapToGlobal(position))

            # Привязка событий к Actions
            if action == addAction:
                text, ok = QInputDialog().getText(self, "Название события",
                                                  "Ввкдите название события:",
                                                  QLineEdit.Normal, '')
                if ok:
                    text = 'Новое событие' if text == '' else text
                    res = self.db.add_event({
                        'alid': self.alid,
                        'event_head': text
                    })
                    if len(res) == 1:
                        event = res[0]
                        text = event['event_head'] if type(event) == type(
                            {}
                        ) and 'event_head' in event.keys(
                        ) and event['event_head'] != '' else 'Новое событие'
                        item = QListWidgetItem(text)
                        item.setWhatsThis(str(event['eid']))
                        self.listWidget.addItem(item)
                        db.events.save()
                        #self.changed = True
                self.event_ids = db.get_all_event_ids(self.alid)

            if action == editAction:
                eid = self.listWidget.currentItem()
                if eid is not None:
                    eid = self.listWidget.currentItem().whatsThis()
                    last_name = self.db.get_event_data(self.alid,
                                                       eid)['event_head']
                    text, ok = QInputDialog().getText(
                        self, "Название события",
                        "Ввкдите новое название события:", QLineEdit.Normal,
                        str(last_name))
                    if ok:
                        event = self.db.edit_event({
                            'alid': self.alid,
                            'eid': eid,
                            'event_head': text
                        })
                        self.listWidget.currentItem().setText(text)
                        self.db.events.save()
                        if event:
                            event = self.db.get_event_data(alid, eid)
                            #b = layout.takeAt(1)
                            self.dictViewer.close()
                            #b.widget().deleteLater()
                            self.dictViewer = DictViewer(
                                event, 1, self.db.events.invizible_fields,
                                self.db.events.editable_fields)
                            self.layout.addWidget(self.dictViewer, 0, 2)
                    self.event_ids = db.get_all_event_ids(self.alid)

            if action == delAction:
                res = QMessageBox.question(
                    self, 'ВНИМАНИЕ!!!',
                    "Вы действительно хотите удалить событие?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if res == QMessageBox.Yes:
                    eid = self.listWidget.currentItem()
                    if eid is not None:
                        eid = self.listWidget.currentItem().whatsThis()
                        self.db.del_event({'alid': self.alid, 'eid': eid})
                        self.listWidget.takeItem(self.listWidget.currentRow())
                        self.db.events.save()
                        #self.changed = True
                    self.event_ids = db.get_all_event_ids(self.alid)

            if action == delAllAction:
                res = QMessageBox.question(
                    self, 'ВНИМАНИЕ!!!',
                    "Вы действительно хотите удалить все события?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if res == QMessageBox.Yes:
                    if self.db.del_all_events(int(self.alid)):
                        self.listWidget.clear()
                        self.db.events.save()
                        #self.changed = True
                    self.event_ids = db.get_all_event_ids(self.alid)

                    #db.photos.save()

            if action == quitAction:
                self.accept()

        self.listWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.listWidget.customContextMenuRequested.connect(openMenu)

        layout.addWidget(self.listWidget, 0, 0, 1, 1)
        layout.addWidget(self.photo_gallery, 0, 1, 1, 1)

        self.setLayout(layout)

    def doubleClick(self, item):
        if item is not None:
            eid = item.whatsThis()
            text = self.db.get_event_path(self.alid, eid)
            print(eid)

    def closeEvent(self, event):
        if self.last_eid:
            self.check_and_save(self.last_eid)

    def itemChanged(self):
        if self.last_eid:
            self.check_and_save(self.last_eid)

        eid = self.listWidget.currentItem()
        if eid is not None:
            eid = self.listWidget.currentItem().whatsThis()
            event = self.db.get_event_data(self.alid, eid)

            if self.photo_gallery:
                self.photo_gallery.close()

            # Работаем с фотками
            self.photo_gallery = QLabelM(self.alid, self.db, 1, eid)
            self.layout.addWidget(self.photo_gallery, 0, 1,
                                  int(self.db.events.nkeys / 2), 1)

            # Заполняем данными
            self.fill_event_data(event)

            print(event)
            self.last_eid = eid
        self.setFocus()
        #print('item changed = ' + str(eid))

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Left:
            #print('left pressed')
            if type(self.photo_gallery) == self.QLABELM_TYPE:
                self.photo_gallery.prev_show()
        if event.key() == Qt.Key_Right:
            #print('right pressed')
            if type(self.photo_gallery) == self.QLABELM_TYPE:
                self.photo_gallery.next_show()
        #super().keyPressEvent(event)

    def fill_event_data(self, event):
        if type(event) != type({}):
            return

        self.dictViewer.close()
        self.dictViewer = DictViewer(event, 1, self.db.events.invizible_fields,
                                     self.db.events.editable_fields)
        self.layout.addWidget(self.dictViewer, 0, 2, 1, 1)

    def check_and_save(self, eid):
        print('check_and_save' + str(eid))
        changes = self.dictViewer.get_changes()
        event = self.db.get_event_data(self.alid, eid)

        if self.photo_gallery.changed:
            changes['photo_ids'] = self.photo_gallery.photo_ids
        print(changes)
        if len(changes) > 0 and type(event) == type({}):
            print('event changes saved')
            event.update(changes)
            self.db.edit_event(event)
            self.db.events.save()
 def _remove_addr(self, qlist: QListWidget, addr):
     for i in range(qlist.count()):
         qitem = qlist.item(i)
         if int(qitem.text(), 16) == addr:
             qlist.takeItem(i)
             return
class MainFrame(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # Define buttons
        # Button to calculate lunar dates
        self.calculate_lunar = QPushButton('음력날짜 계산', self)
        self.calculate_lunar.clicked.connect(self.calculate_lunar_date)
        self.calculate_lunar.setGeometry(20, 260, 130, 35)
        self.calculate_lunar.setStatusTip('음력 날짜를 계산합니다.')
        self.calculate_lunar.setShortcut('Return')

        # Button to save ICS file to local directory
        self.ICS_save_button = QPushButton('ICS 파일 저장', self)
        self.ICS_save_button.clicked.connect(self.create_ics_file)
        self.ICS_save_button.setGeometry(175, 260, 130, 35)
        self.ICS_save_button.setStatusTip('ICS 파일을 컴퓨터에 저장합니다.')

        # Define labels
        # Define label for lunar date to convert
        lunar_date_text = QLabel(self)
        lunar_date_text.setText('계산할 음력 날짜')
        lunar_date_text.setGeometry(25, 15, 240, 25)

        # Define label for name of event
        event_name_text = QLabel(self)
        event_name_text.setText('이벤트 이름 입력')
        event_name_text.setGeometry(25, 50, 240, 25)

        # Define label for repetition
        event_name_text = QLabel(self)
        event_name_text.setText('몇년치나 할까요?')
        event_name_text.setGeometry(25, 85, 240, 25)

        # Define ListWidget to display results
        self.result_console = QListWidget(self)
        self.result_console.setGeometry(25, 118, 275, 133)
        self.result_console.setStatusTip('올해부터 매년 양력날짜가 출력됩니다.')

        # Define user input areas
        # Define lunar date to convert to solar date
        self.user_date_input = QLineEdit(self)
        self.user_date_input.setGeometry(180, 15, 120, 27)
        self.user_date_input.setAlignment(Qt.AlignCenter)
        self.user_date_input.setPlaceholderText('YYYYMMDD')
        self.user_date_input.setStatusTip('날짜를 YYYYMMDD로 입력하세요.')

        # Define name of event to use in ICS file
        self.user_event_name = QLineEdit(self)
        self.user_event_name.setGeometry(180, 50, 120, 27)
        self.user_event_name.setAlignment(Qt.AlignCenter)
        self.user_event_name.setPlaceholderText('이벤트 이름')
        self.user_event_name.setStatusTip('이벤트 이름을 입력하세요.')

        # Define number of years to convert
        self.user_repetition = QLineEdit(self)
        self.user_repetition.setGeometry(180, 84, 120, 27)
        self.user_repetition.setAlignment(Qt.AlignCenter)
        self.user_repetition.setText('10')
        self.user_repetition.setStatusTip('생성할 햇수를 입력하세요.')

        # Define size of main window
        self.setGeometry(200, 320, 325, 330)
        self.setWindowTitle('날짜')
        self.statusBar()
        self.show()

    # Define functions
    # Function to parse lunar date from openAPI website using user input
    def calculate_lunar_date(self):
        if len(self.user_date_input.text()) != 8:
            reply = QMessageBox.question(self, 'Error',
                                         "YYYYMMDD로 정확한 날짜를 입력해 주십시오.",
                                         QMessageBox.Close)
            return

        url = 'http://apis.data.go.kr/B090041/openapi/service/LrsrCldInfoService/getSolCalInfo'
        personal_key = 'UrEdHGIOCJr600RsRQ%2BnoL2wma3HT9JXmYn0uhHwmxImsnE2GHKYfn1RUfiEK9RIHXPJ3FBRnONxXMjplU3%2F7g%3D%3D'
        lunar_input = self.user_date_input.text()
        lunar_month = lunar_input[4:6]
        lunar_day = lunar_input[6:]
        repeat = int(self.user_repetition.text()) + 1

        for i in range(0, repeat):
            lunar_year = int(lunar_input[:4]) + int(i)
            # Limit search at lunar year 2050.
            if lunar_year > 2050:
                break

            query_params = '?lunYear={}&lunMonth={}&lunDay={}&ServiceKey={}'.format(
                lunar_year, lunar_month, lunar_day, personal_key)
            session = XMLSession()
            r = session.get(url + query_params)
            solar_day = r.xml.xpath('//solDay', first=True).text
            solar_month = r.xml.xpath('//solMonth', first=True).text
            solar_year = r.xml.xpath('//solYear', first=True).text
            solar_week = r.xml.xpath('//solWeek', first=True).text
            solar_date_text = '   {}년 {}월 {}일 {}요일 '.format(
                solar_year, solar_month, solar_day, solar_week)

            QListWidgetItem(solar_date_text, self.result_console)

    def create_ics_file(self):
        event_name = self.user_event_name.text()
        ics_content = 'BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\nBEGIN:VTIMEZONE\nTZID:Asia/Tokyo\n' \
                      'TZURL:http://tzurl.org/zoneinfo-outlook/Asia/Tokyo\nX-LIC-LOCATION:Asia/Tokyo\n' \
                      'BEGIN:STANDARD\nTZOFFSETFROM:+0900\nTZOFFSETTO:+0900\nTZNAME:JST\n' \
                      'DTSTART:19700101T000000\nEND:STANDARD\nEND:VTIMEZONE\n'

        if len(self.user_event_name.text()) == 0:
            reply = QMessageBox.question(self, 'Error', "이벤트 이름을 입력해 주십시오.",
                                         QMessageBox.Close)
            return
        elif self.result_console.count() == 0:
            reply = QMessageBox.question(self, 'Error', "날짜 계산을 먼저 해주십시오.",
                                         QMessageBox.Close)
            return

        # Iterate through QListWidget items: https://stackoverflow.com/a/34479509
        converted_dates = [
            str(self.result_console.item(i).text())
            for i in range(self.result_console.count())
        ]
        for i in converted_dates:
            # Extract digits from string: https://stackoverflow.com/a/26825833
            date_string = (''.join(filter(str.isdigit, i)))
            event_string = 'BEGIN:VEVENT\nDTSTAMP:20180802T115053z\nDTSTART;TZID="Asia/Tokyo":{0}T120000' \
                           '\nDTEND;TZID="Asia/Tokyo":{0}T120000\nSUMMARY:{1}\nBEGIN:VALARM\n' \
                           'TRIGGER:-PT14H\nREPEAT:1\nACTION:DISPLAY\nDESCRIPTION:Reminder\nEND:VALARM\nEND:VEVENT\n'
            ics_content += event_string.format(date_string, event_name)

        ics_content += 'END:VCALENDAR'

        # This program cannot read existing .ics files, so if user creates a new ics event with existing file name,
        # the program would crash.
        new_ics = open(event_name.replace(' ', '') + '.ics', 'w')
        new_ics.write(ics_content)
        new_ics.close()

        success = QMessageBox.question(self, 'Success', "ICS 파일 생성 완료!",
                                       QMessageBox.Close)
Example #21
0
class LevelSelector(QDialog):
    def __init__(self, parent):
        super(LevelSelector, self).__init__(parent)

        self.setWindowTitle("Level Selector")
        self.setModal(True)

        self.selected_world = 1
        self.selected_level = 1
        self.object_set = 0
        self.object_data_offset = 0x0
        self.enemy_data_offset = 0x0

        self.world_label = QLabel(parent=self, text="World")
        self.world_list = QListWidget(parent=self)
        self.world_list.addItems(WORLD_ITEMS)

        self.world_list.itemDoubleClicked.connect(self.on_ok)
        self.world_list.itemSelectionChanged.connect(self.on_world_click)

        self.level_label = QLabel(parent=self, text="Level")
        self.level_list = QListWidget(parent=self)

        self.level_list.itemDoubleClicked.connect(self.on_ok)
        self.level_list.itemSelectionChanged.connect(self.on_level_click)

        self.enemy_data_label = QLabel(parent=self, text="Enemy Data")
        self.enemy_data_spinner = Spinner(parent=self)

        self.object_data_label = QLabel(parent=self, text="Object Data")
        self.object_data_spinner = Spinner(self)

        self.object_set_label = QLabel(parent=self, text="Object Set")
        self.object_set_dropdown = QComboBox(self)
        self.object_set_dropdown.addItems(OBJECT_SET_ITEMS)

        self.button_ok = QPushButton("Ok", self)
        self.button_ok.clicked.connect(self.on_ok)
        self.button_cancel = QPushButton("Cancel", self)
        self.button_cancel.clicked.connect(self.close)

        self.window_layout = QGridLayout(self)

        self.window_layout.addWidget(self.world_label, 0, 0)
        self.window_layout.addWidget(self.level_label, 0, 1)

        self.window_layout.addWidget(self.world_list, 1, 0)
        self.window_layout.addWidget(self.level_list, 1, 1)

        self.window_layout.addWidget(self.enemy_data_label, 2, 0)
        self.window_layout.addWidget(self.object_data_label, 2, 1)
        self.window_layout.addWidget(self.enemy_data_spinner, 3, 0)
        self.window_layout.addWidget(self.object_data_spinner, 3, 1)

        self.window_layout.addWidget(self.object_set_label, 4, 0)
        self.window_layout.addWidget(self.object_set_dropdown, 4, 1)

        self.window_layout.addWidget(self.button_ok, 5, 0)
        self.window_layout.addWidget(self.button_cancel, 5, 1)

        self.setLayout(self.window_layout)

        self.world_list.setCurrentRow(1)  # select Level 1-1
        self.on_world_click()

    def keyPressEvent(self, key_event: QKeyEvent):
        if key_event.key() == Qt.Key_Escape:
            self.reject()

    def on_world_click(self):
        index = self.world_list.currentRow()

        assert index >= 0

        self.level_list.clear()

        # skip first meaningless item
        for level in Level.offsets[1:]:
            if level.game_world == index:
                if level.name:
                    self.level_list.addItem(level.name)

        if self.level_list.count():
            self.level_list.setCurrentRow(0)

            self.on_level_click()

    def on_level_click(self):
        index = self.level_list.currentRow()

        assert index >= 0

        self.selected_world = self.world_list.currentRow()
        self.selected_level = index + 1

        level_is_overworld = self.selected_world == OVERWORLD_MAPS_INDEX

        if level_is_overworld:
            level_array_offset = self.selected_level
        else:
            level_array_offset = Level.world_indexes[self.selected_world] + self.selected_level

        object_data_for_lvl = Level.offsets[level_array_offset].rom_level_offset

        if not level_is_overworld:
            object_data_for_lvl -= Level.HEADER_LENGTH

        self.object_data_spinner.setValue(object_data_for_lvl)

        if not level_is_overworld:
            enemy_data_for_lvl = Level.offsets[level_array_offset].enemy_offset
        else:
            enemy_data_for_lvl = 0

        if enemy_data_for_lvl > 0:
            # data in look up table is off by one, since workshop ignores the first byte
            enemy_data_for_lvl -= 1

        self.enemy_data_spinner.setValue(enemy_data_for_lvl)
        self.enemy_data_spinner.setEnabled(not level_is_overworld)

        # if self.selected_world >= WORLD_1_INDEX:
        object_set_index = Level.offsets[level_array_offset].real_obj_set
        self.object_set_dropdown.setCurrentIndex(object_set_index)

        self.button_ok.setDisabled(self.selected_world == 0)

    def on_ok(self, _):
        if self.selected_world == 0:
            return

        self.object_set = self.object_set_dropdown.currentIndex()
        self.object_data_offset = self.object_data_spinner.value()
        # skip the first byte, because it seems useless
        self.enemy_data_offset = self.enemy_data_spinner.value() + 1

        self.accept()

    def closeEvent(self, _close_event: QCloseEvent):
        self.reject()
class AddMovieDialog(QDialog):
    client = Client()

    def __init__(self, parent):
        super(AddMovieDialog, self).__init__(parent)
        self.setWindowTitle("Add Movie")
        main_layout = QVBoxLayout(self)

        self.selected_movies = None

        search_layout = QHBoxLayout()
        main_layout.addLayout(search_layout)

        self.search_field = QLineEdit()
        self.search_field.returnPressed.connect(self.find_action)
        self.search_field.setPlaceholderText("Search movies...")
        search_layout.addWidget(self.search_field)

        self.find_all_checkbx = QCheckBox("Find All")
        search_layout.addWidget(self.find_all_checkbx)

        self.result_list = QListWidget()
        self.result_list.setSelectionMode(QListWidget.ExtendedSelection)
        main_layout.addWidget(self.result_list)

        button_layout = QHBoxLayout()
        main_layout.addLayout(button_layout)

        add_bttn = QPushButton("Add Movie")
        add_bttn.clicked.connect(self.accept)

        add_all_bttn = QPushButton("Add All Movies")
        add_all_bttn.clicked.connect(self.add_all_action)

        cancel_bttn = QPushButton("Cancel")
        cancel_bttn.clicked.connect(self.reject)

        button_layout.addWidget(add_bttn)
        button_layout.addWidget(add_all_bttn)
        button_layout.addWidget(cancel_bttn)

    def keyPressEvent(self, event):
        event.ignore()

    def add_all_action(self):
        for i in range(self.result_list.count()):
            self.result_list.setItemSelected(self.result_list.item(i), True)

        self.accept()

    def accept(self):
        selected_items = self.result_list.selectedItems()
        if not selected_items:
            return

        self.selected_movies = [
            i.movie_data for i in selected_items
            if not self.client.find_movie(i.movie_data["id"])
        ]
        super(AddMovieDialog, self).accept()

    def find_action(self):
        movie_title = self.search_field.text()
        if len(movie_title):
            self.result_list.clear()

            for item in find_movie(
                    movie_title, all_pages=self.find_all_checkbx.isChecked()):
                MovieItem(self.result_list, item)
Example #23
0
class PersonaUI(QWidget):
    """
    Widget for Persona creation view.

    :param MainFrame mainframe: application mainframe
    :param QWidget op: parent widget
    """
    def __init__(self, mainframe, op):
        QWidget.__init__(self)
        self.mainframe = mainframe
        self.op = op

        self.grid = QGridLayout()
        self.setLayout(self.grid)

        self.listP = None
        self.listLS = None
        self.listEL1 = None
        self.listEL2 = None

        self.nameT = None
        self.levelT = None
        self.textT = None
        self.strT = None
        self.magT = None
        self.endT = None
        self.agiT = None
        self.luckT = None

        self.createFrame = None
        self.buttonFrame = None
        self.bfgrid = None
        # Actual create frame variables.
        self.cfgrid = None
        self.lsdic = None
        self.slashO = None
        self.strikeO = None
        self.pierceO = None
        self.fireO = None
        self.iceO = None
        self.windO = None
        self.elecO = None
        self.darkO = None
        self.lightO = None
        self.arcO = None
        self.iSpellOs = None
        self.lsSpellO = None
        self.lslevel = None


        self.initUI(True)

    def initUI(self, infoDump):
        """
        Initializes the basic UI showing the list of Personas.
        Does a lot of stuff.

        :param dict infoDump: not sure lol
        """
        self.mainframe.setWindowTitle("Persona Creator")

        if not infoDump:
            self.createFrameDraw()

        self.initButtonFrame(infoDump)

        self.listP = QListWidget(self)
        self.grid.addWidget(self.listP, 0, 3, 2, 1)
        temp = json_reader.readPerNames()
        self.listP.addItems(temp)

    def initButtonFrame(self, infoDump):
        """
        Initializes the buttonframes that are present in all Persona creator views.

        :param dict infoDump: not sure lol
        """
        self.buttonFrame = QWidget(self)
        self.bfgrid = QGridLayout()
        self.buttonFrame.setLayout(self.bfgrid)

        self.grid.addWidget(self.buttonFrame, 3, 0, 1, 4)


        new = QPushButton(self.buttonFrame, text="New")
        new.clicked.connect(self.new)
        self.bfgrid.addWidget(new, 4, 0)

        back = QPushButton(self.buttonFrame, text="Back")
        back.clicked.connect(self.back)
        self.bfgrid.addWidget(back, 4, 4)

        remove = QPushButton(self.buttonFrame, text="Remove")
        remove.clicked.connect(self.remove)
        self.bfgrid.addWidget(remove, 4, 3)

        edit = QPushButton(self.buttonFrame, text="Edit")
        edit.clicked.connect(self.edit)
        self.bfgrid.addWidget(edit, 4, 2)

        if not infoDump:
            save = QPushButton(self.buttonFrame, text="Save")
            save.clicked.connect(self.save)
            self.bfgrid.addWidget(save, 4, 1)


    def createFrameDraw(self):
        """
        Initializes the GUI of the actual creation frame view.
        Does a LOT of stuff.
        """
        self.createFrame = QWidget(self)
        self.cfgrid = QGridLayout()
        self.createFrame.setLayout(self.cfgrid)
        self.grid.addWidget(self.createFrame, 0, 0, 2, 2)

        self.lsdic = {}

        nameL = QLabel(self.createFrame, text="Name:")
        self.cfgrid.addWidget(nameL, 0, 0)
        self.nameT = QLineEdit(self.createFrame)
        self.nameT.setFixedSize(100, 20)
        self.cfgrid.addWidget(self.nameT, 0, 1)

        strL = QLabel(self.createFrame, text="Str")
        self.cfgrid.addWidget(strL, 0, 2)
        self.strT = QLineEdit(self.createFrame)
        self.strT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.strT, 0, 3)
        magL = QLabel(self.createFrame, text="Mag")
        self.cfgrid.addWidget(magL, 1, 2)
        self.magT = QLineEdit(self.createFrame)
        self.magT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.magT, 1, 3)
        endL = QLabel(self.createFrame, text="End")
        self.cfgrid.addWidget(endL, 2, 2)
        self.endT = QLineEdit(self.createFrame)
        self.endT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.endT, 2, 3)
        agiL = QLabel(self.createFrame, text="Agi")
        self.cfgrid.addWidget(agiL, 3, 2)
        self.agiT = QLineEdit(self.createFrame)
        self.agiT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.agiT, 3, 3)
        luckL = QLabel(self.createFrame, text="Luck")
        self.cfgrid.addWidget(luckL, 4, 2)
        self.luckT = QLineEdit(self.createFrame)
        self.luckT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.luckT, 4, 3)

        resList = json_reader.data_list("resistances")
        resL = QLabel(self.createFrame, text="Resistance:")
        self.cfgrid.addWidget(resL, 0, 5)
        slashL = QLabel(self.createFrame, text="Slash")
        self.cfgrid.addWidget(slashL, 1, 5)
        self.slashO = QComboBox(self.createFrame)
        self.slashO.addItems(resList)
        self.slashO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.slashO, 1, 6)
        strikeL = QLabel(self.createFrame, text="Strike")
        self.cfgrid.addWidget(strikeL, 2, 5)
        self.strikeO = QComboBox(self.createFrame)
        self.strikeO.addItems(resList)
        self.strikeO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.strikeO, 2, 6)
        pierceL = QLabel(self.createFrame, text="Pierce")
        self.cfgrid.addWidget(pierceL, 3, 5)
        self.pierceO = QComboBox(self.createFrame)
        self.pierceO.addItems(resList)
        self.pierceO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.pierceO, 3, 6)
        fireL = QLabel(self.createFrame, text="Fire")
        self.cfgrid.addWidget(fireL, 4, 5)
        self.fireO = QComboBox(self.createFrame)
        self.fireO.addItems(resList)
        self.fireO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.fireO, 4, 6)
        iceL = QLabel(self.createFrame, text="Ice")
        self.cfgrid.addWidget(iceL, 5, 5)
        self.iceO = QComboBox(self.createFrame)
        self.iceO.addItems(resList)
        self.iceO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.iceO, 5, 6)
        elecL = QLabel(self.createFrame, text="Elec")
        self.cfgrid.addWidget(elecL, 6, 5)
        self.elecO = QComboBox(self.createFrame)
        self.elecO.addItems(resList)
        self.elecO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.elecO, 6, 6)
        windL = QLabel(self.createFrame, text="Wind")
        self.cfgrid.addWidget(windL, 7, 5)
        self.windO = QComboBox(self.createFrame)
        self.windO.addItems(resList)
        self.windO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.windO, 7, 6)
        lightL = QLabel(self.createFrame, text="Light")
        self.cfgrid.addWidget(lightL, 8, 5)
        self.lightO = QComboBox(self.createFrame)
        self.lightO.addItems(resList)
        self.lightO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.lightO, 8, 6)
        darkL = QLabel(self.createFrame, text="Dark")
        self.cfgrid.addWidget(darkL, 9, 5)
        self.darkO = QComboBox(self.createFrame)
        self.darkO.addItems(resList)
        self.darkO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.darkO, 9, 6)

        spellList = json_reader.data_list("spells")
        self.listLS = QListWidget(self.createFrame)
        self.listLS.setFixedSize(200, 300)
        self.cfgrid.addWidget(self.listLS, 3, 7, 8, 2)

        newLS = QPushButton(self.createFrame, text="+")
        newLS.clicked.connect(self.addLS)
        self.cfgrid.addWidget(newLS, 2, 7)
        delLS = QPushButton(self.createFrame, text="DEL")
        delLS.clicked.connect(self.delLS)
        self.cfgrid.addWidget(delLS, 2, 8)

        lsl = QLabel(self.createFrame, text="Learned Spells:")
        self.cfgrid.addWidget(lsl, 0, 7, 1, 2)

        arcanaL = QLabel(self.createFrame, text="Arcana:")
        self.cfgrid.addWidget(arcanaL, 1, 0)
        arc_list = json_reader.data_list("arcanas")
        self.arcO = QComboBox(self.createFrame)
        self.arcO.addItems(arc_list)
        self.arcO.setCurrentIndex(0)
        self.cfgrid.addWidget(self.arcO, 1, 1)

        levelL = QLabel(self.createFrame, text="Level:")
        self.cfgrid.addWidget(levelL, 2, 0)
        self.levelT = QLineEdit(self.createFrame)
        self.levelT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.levelT, 2, 1)

        heritageL = QLabel(self.createFrame, text="Inherits:")
        self.cfgrid.addWidget(heritageL, 3, 0, 1, 2)

        elements = json_reader.data_list("elements")
        elements.append("Support")
        self.listEL1 = QComboBox(self.createFrame)
        self.listEL1.addItems(elements)
        self.cfgrid.addWidget(self.listEL1, 4, 0)
        self.listEL2 = QComboBox(self.createFrame)
        self.listEL2.addItems(elements)
        self.cfgrid.addWidget(self.listEL2, 4, 1)

        iSpellL = QLabel(self.createFrame, text="Initial Spells:")
        self.cfgrid.addWidget(iSpellL, 5, 0, 1, 2)
        self.iSpellOs = []
        for i in range(6, 9):
            temp = QComboBox(self.createFrame)
            temp.addItems(spellList)
            temp2 = QComboBox(self.createFrame)
            temp2.addItems(spellList)
            self.cfgrid.addWidget(temp, i, 0, 1, 2)
            self.cfgrid.addWidget(temp2, i, 2, 1, 2)
            self.iSpellOs.extend([temp, temp2])

        textL = QLabel(self.createFrame, text="Info:")
        self.cfgrid.addWidget(textL, 10, 0)
        self.textT = QTextEdit(self.createFrame)
        self.textT.setFixedSize(300, 100)
        self.cfgrid.addWidget(self.textT, 10, 1, 1, 5)

        self.lslevel = QLineEdit(self.createFrame)
        self.lslevel.setFixedSize(40, 20)
        self.lsSpellO = QComboBox(self.createFrame)
        self.lsSpellO.addItems(spellList)

        self.cfgrid.addWidget(self.lsSpellO, 1, 7)
        self.cfgrid.addWidget(self.lslevel, 1, 8)

    def addLS(self):
        """
        Add a learned spell to the list, based on what was entered.
        """
        print("Adding learned spell")
        chosenSpell = self.lsSpellO.currentText()
        if (int)(self.lslevel.text()) <= (int)(self.levelT.text()):
            popup("You cannot add a spell at an earlier level than the Persona's base level", "Critical")
            return
        if chosenSpell != "":
            print("Ok")
            self.lsdic[chosenSpell] = self.lslevel.text()
            self.listLS.addItem(chosenSpell + " at level " + self.lslevel.text())
            self.lslevel.setText("")
            self.lsSpellO.setCurrentIndex(0)
            return
        popup("You must choose a spell", "Critical")

    def delLS(self):
        """
        Remove the selected learned spell from the list
        """
        print("Deleting learned spell")
        key = ""
        i = 0
        while len(self.listLS.currentItem().text()) > i:
            if self.listLS.currentItem().text()[i] == " " and \
               self.listLS.currentItem().text()[i+1] == "a" and \
               self.listLS.currentItem().text()[i+2] == "t":  # TODO EWWWWWW
                break
            key += self.listLS.currentItem().text()[i]
            i = i + 1
        print(key)
        print(self.lsdic.pop(key))
        self.listLS.takeItem(self.listLS.currentRow())


    def loadPer(self, name):
        """
        Load a certain Persona from file.

        :param str name: name of Persona to load
        """
        data = json_reader.readOne(name, 'pers')
        self.nameT.setText(data["name"])
        self.textT.setText(data["desc"])
        self.strT.setText(data["stats"][0])
        self.magT.setText(data["stats"][1])
        self.endT.setText(data["stats"][2])
        self.agiT.setText(data["stats"][3])
        self.luckT.setText(data["stats"][4])
        self.levelT.setText(data["level"])

        self.arcO.setCurrentIndex(
            [self.arcO.itemText(i) for i in range(self.arcO.count())].index(data["arcana"])
        )

        self.listEL1.setCurrentIndex(
            [self.listEL1.itemText(i) for i in range(self.listEL1.count())].index(data["heritage"][0])
        )
        self.listEL2.setCurrentIndex(
            [self.listEL2.itemText(i) for i in range(self.listEL2.count())].index(data["heritage"][1])
        )

        self.slashO.setCurrentIndex(
            [self.slashO.itemText(i) for i in range(self.slashO.count())].index(data["resistance"][0])
        )
        self.strikeO.setCurrentIndex(
            [self.strikeO.itemText(i) for i in range(self.strikeO.count())].index(data["resistance"][1])
        )
        self.pierceO.setCurrentIndex(
            [self.pierceO.itemText(i) for i in range(self.pierceO.count())].index(data["resistance"][2])
        )
        self.fireO.setCurrentIndex(
            [self.fireO.itemText(i) for i in range(self.fireO.count())].index(data["resistance"][3])
        )
        self.iceO.setCurrentIndex(
            [self.iceO.itemText(i) for i in range(self.iceO.count())].index(data["resistance"][4])
        )
        self.elecO.setCurrentIndex(
            [self.elecO.itemText(i) for i in range(self.elecO.count())].index(data["resistance"][5])
        )
        self.windO.setCurrentIndex(
            [self.windO.itemText(i) for i in range(self.windO.count())].index(data["resistance"][6])
        )
        self.lightO.setCurrentIndex(
            [self.lightO.itemText(i) for i in range(self.lightO.count())].index(data["resistance"][7])
        )
        self.darkO.setCurrentIndex(
            [self.darkO.itemText(i) for i in range(self.darkO.count())].index(data["resistance"][8])
        )

        i = 0
        for combobox in self.iSpellOs:
            combobox.setCurrentIndex(
                [combobox.itemText(j) for j in range(combobox.count()-1)].index(data["spellDeck"][i])
            )
            i += 1

        self.lsdic = data["spellLearn"]
        self.listLS.clear()
        for spell, level in self.lsdic.items():
            self.listLS.addItem(spell + " at level " + level)

        print("Loaded " + data["name"])

    def edit(self):
        """
        Switch to edit view, also loads the selected Persona.
        """
        try:
            if self.listP.currentItem().text() != "":
                if self.createFrame and not popup("Override any unsaved changes?", "Warning"):
                    return
                self.loadPer(self.listP.currentItem().text())
        except AttributeError:  # To initialize createFrame UI before load
            if self.listP.currentItem().text() != "":
                temp = self.listP.currentItem().text()
                self.buttonFrame.close()
                self.initUI(False)
                self.loadPer(temp)
            else:
                return
        self.createFrame.show()
        self.mainframe.center()
        print("Changed to edit frame")

    def save(self):
        """
        Validate all info and save to file on disk.
        """
        if os.path.exists(json_reader.buildPath("data/pers/"+self.nameT.text()+".json")):
            if not popup("Override existing Persona "+self.nameT.text()+"?", "Question"):
                return
        print("Saving")
        spellDeck = []
        for combobox in self.iSpellOs:
            spellDeck.append(combobox.currentText())
        stats = [self.strT.text(), self.magT.text(), self.endT.text(), self.agiT.text(), self.luckT.text()]
        res = [self.slashO.currentText(), self.strikeO.currentText(), self.pierceO.currentText(),
               self.fireO.currentText(), self.iceO.currentText(), self.elecO.currentText(),
               self.windO.currentText(), self.lightO.currentText(), self.darkO.currentText()]
        try:
            (int)(self.levelT.text())
            (int)(self.strT.text())
            (int)(self.magT.text())
            (int)(self.endT.text())
            (int)(self.agiT.text())
            (int)(self.luckT.text())
        except ValueError:
            popup("There is a number entry that isn't valid.\nEntries requiring numbers are:\nLEVEL\nSTR"
                  "\nMAG\nEND\nAGI\nLUCK", "Critical")
            print("Not Saved")
            return
        if not (self.nameT.text() and not self.nameT.text().isspace()):
            popup("No name entered for your Persona. Name is a required field.", "Critical")
            print("No Name, not saved")
            return
        toWrite = Persona(
            self.nameT.text(),
            self.arcO.currentText(),
            self.levelT.text(),
            self.textT.toPlainText(),
            spellDeck,
            self.lsdic,
            stats,
            res,
            [self.listEL1.currentText(), self.listEL2.currentText()]
        )
        json_reader.writeOne(toWrite, 'pers')
        temp = self.nameT.text()
        if (temp not in [self.listP.item(i).text() for i in range(self.listP.count())]):
            self.listP.addItem(temp)
        self.loadPer(temp)
        print("Saved Persona")

    def remove(self):
        """
        Remove a created Persona from the list and delete the file on disk.
        """
        if self.listP.currentItem().text() == "":
            return
        if not popup(
                "Are you certain you want to completely remove this Persona?\n(Cannot be undone)", "Warning"
            ):
            return
        print("Removing Persona " + self.listP.currentItem().text())
        json_reader.deletePer(self.listP.currentItem().text())
        self.listP.takeItem(
            [self.listP.item(i).text() for i in range(self.listP.count())].index(
                self.listP.currentItem().text())
        )

    def new(self):
        """
        Open an empty Persona edit view.
        """
        if self.createFrame and not popup("Override any unsaved changes?", "Warning"):
            return
        if self.createFrame:
            self.createFrame.close()
        self.buttonFrame.close()
        self.initUI(False)
        self.createFrame.show()
        self.mainframe.center()
        print("Created")

    def back(self):
        """
        Return to the parent widget.
        """
        print("Returned to main screen")
        self.mainframe.changeState(self.op)
Example #24
0
class QtEpsInfo(QtWidgets.QWidget, Ui_EpsInfo):
    def __init__(self, owner):
        super(self.__class__, self).__init__()
        Ui_EpsInfo.__init__(self)
        self.setupUi(self)
        self.owner = weakref.ref(owner)

        self.epsListWidget = QListWidget()
        self.epsListWidget.setFlow(self.epsListWidget.LeftToRight)
        self.epsListWidget.setWrapping(True)
        self.epsListWidget.setFrameShape(self.epsListWidget.NoFrame)
        self.epsListWidget.setResizeMode(self.epsListWidget.Adjust)
        self.epsListWidget.itemClicked.connect(self.SelectEps)
        self.gridLayout_2.addWidget(self.epsListWidget, 1, 0)
        self.closeFlag = self.__class__.__name__
        self.bookId = ""
        self.loadingForm = QtLoading(self)
        self.setWindowTitle("章节列表")

        self.greed = QColor(18, 161, 130)
        self.blue = QColor(97, 154, 195)
        self.white = QColor(0, 0, 0, 0)

    def OpenEpsInfo(self, bookId):
        self.show()
        self.loadingForm.show()
        self.bookId = bookId
        self.epsListWidget.clear()
        if bookId not in BookMgr().books:
            self.owner().qtTask.AddHttpTask(lambda x: BookMgr().AddBookById(self.bookId, x), self.OpenBookInfoBack,
                                            cleanFlag=self.closeFlag)
        else:
            self.owner().qtTask.AddHttpTask(lambda x: BookMgr().AddBookEpsInfo(self.bookId, x), self.OpenEpsInfoBack,
                                            cleanFlag=self.closeFlag)

    def OpenBookInfoBack(self, msg):
        if msg == Status.Ok:
            self.owner().qtTask.AddHttpTask(lambda x: BookMgr().AddBookEpsInfo(self.bookId, x), self.OpenEpsInfoBack,
                                            cleanFlag=self.closeFlag)
        else:
            self.loadingForm.close()

    def OpenEpsInfoBack(self, msg):
        self.loadingForm.close()
        self.epsListWidget.clear()
        if msg == Status.Ok:
            self.UpdateEpsInfo()
        return

    def UpdateEpsInfo(self):
        self.epsListWidget.clear()
        info = BookMgr().books.get(self.bookId)
        if not info:
            return
        downloadEpsId = self.owner().downloadForm.GetDownloadEpsId(self.bookId)
        for index, epsInfo in enumerate(info.eps):
            label = QLabel(epsInfo.title)
            label.setContentsMargins(20, 10, 20, 10)
            item = QListWidgetItem(self.epsListWidget)
            item.setSizeHint(label.sizeHint())
            if index in downloadEpsId:
                item.setBackground(self.greed)
            else:
                item.setBackground(self.white)
            self.epsListWidget.setItemWidget(item, label)

    def SelectEps(self, item):
        if item.background().color() == self.greed:
            return
        elif item.background().color() == self.blue:
            item.setBackground(self.white)
        else:
            item.setBackground(self.blue)
        return

    def SelectAll(self):
        for i in range(self.epsListWidget.count()):
            item = self.epsListWidget.item(i)
            if item.background().color() == self.greed:
                continue
            item.setBackground(self.blue)
        return

    def CancleSelect(self):
        for i in range(self.epsListWidget.count()):
            item = self.epsListWidget.item(i)
            if item.background().color() == self.greed:
                continue
            item.setBackground(self.white)
        return

    def StartDownload(self):
        downloadIds = []
        for i in range(self.epsListWidget.count()):
            item = self.epsListWidget.item(i)
            if item.background().color() == self.blue:
                downloadIds.append(i)
        if not downloadIds:
            return
        self.owner().downloadForm.AddDownload(self.bookId, downloadIds)
        self.UpdateEpsInfo()
        return
Example #25
0
class CreateSequenceWindow(QDialog):
    """
    Window for creating a new sequence
    """
    def __init__(self,
                 motors={},
                 listOfSequenceHandler=None,
                 sequence=None,
                 modifySequence=False):
        """
        Initializtion of the window for creating a new sequence
        :param motors: The dictionary of all the motors
        :param listOfSequenceHandler: The handler of the list of sequence
        """
        QDialog.__init__(self)
        # Set the window icon
        appIcon = QIcon(icon)
        self.setWindowIcon(appIcon)

        ## Flag if the sequence is a modified one or a new one
        self.__modifySequence = modifySequence
        ## The handler of the list of sequence
        self.__listOfSequenceHandler = listOfSequenceHandler
        ## The dictionary of all the motors
        self.__motors = motors
        ## The new sequence
        self.__sequence = sequence
        ## A dictionary of the positions of the new sequence
        self.__wantedPositions = {}
        ## The layout of the create sequence window
        self.__layout = QVBoxLayout(self)
        ## The widget for the name of the sequenc
        self.nameEntry = QLineEdit()
        self.nameEntry.setText(self.__sequence.getName())
        ## The label for the widget in which the name of the sequence is written
        self.__nameLabel = QLabel("Sequence Name")
        ## The list of the different moves that forms the sequence
        self.__listOfMoveLabels = QListWidget()
        moveNumber = 1
        for move in self.__sequence.getMoves():
            # Set text for the move label
            labelText = "move " + str(moveNumber) + ": "
            moveNumber += 1
            for motor in self.__motors:
                labelText += self.__motors[motor].getName() + " " + \
                             str(move.getMotorPosition(self.__motors[motor].getName())) + ", "
            label = moveLabel(move, labelText, self.__motors)

            # insert label to the head of the list
            self.__listOfMoveLabels.insertItem(0, label)

        # Put the sliders of the create sequence window in a list
        ## List of sliders in the create sequence window
        self.listOfSliders = []
        dictOfSlider = dict()

        for motor in self.__motors:
            dictOfSlider[motor] = QSlider(Qt.Horizontal)
            dictOfSlider[motor].setMaximum(4095)
            dictOfSlider[motor].setValue(
                self.__motors[motor].getCurrentPosition())
            dictOfSlider[motor].sliderMoved.connect(
                self.__motors[motor].setGoalPosition)
            self.listOfSliders.append(dictOfSlider[motor])

        ## Message to make the user put a name to the sequence
        self.__noNameMessage = QMessageBox()
        self.__noNameMessage.setIcon(QMessageBox.Warning)
        self.__noNameMessage.setWindowIcon(appIcon)
        self.__noNameMessage.setText(
            "Please name your sequence before saving it")
        self.__noNameMessage.setStandardButtons(QMessageBox.Ok)
        # Renable the create sequence window and closes the message
        self.__noNameMessage.accepted.connect(self.enableWindow)

        ## Warning message to make sure the user doen't want to save the sequence
        self.__warningMessage = QMessageBox()
        self.__warningMessage.setIcon(QMessageBox.Warning)
        self.__warningMessage.setWindowIcon(appIcon)
        self.__warningMessage.setText(
            "Are you sure you want to close this window? Your sequence will not be saved"
        )
        self.__warningMessage.setStandardButtons(QMessageBox.Ok
                                                 | QMessageBox.Cancel)
        # Close the create sequence window and the message
        self.__warningMessage.accepted.connect(self.reject)
        # Renable the create sequence window and closes the message
        self.__warningMessage.rejected.connect(self.enableWindow)

        # Set the text for the labels
        ## Labels for the motors in the UI
        self.__motorLabels = []
        for motorNumber in range(0, len(motors)):
            self.__motorLabels.append(
                QLabel("Motor " + str(motorNumber + 1) + " position"))

        ## Button to add a move to the sequence and procede to the next move
        self.nextMoveButton = QPushButton("Save Move")

        ## Buttons to accept or cancel the creation of a sequence
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        # If ok pressed add the sequence to the list
        self.buttonBox.accepted.connect(
            lambda: self.addSequenceToList(self.__modifySequence))
        # If cancel pressed close the create sequence window
        self.buttonBox.rejected.connect(self.__warningMessage.exec)

        # Renable the main window when the create sequence closes
        self.rejected.connect(self.__listOfSequenceHandler.enableUi)
        self.accepted.connect(self.__listOfSequenceHandler.enableUi)

        self.nextMoveButton.clicked.connect(self.addMovetoSequence)

        self.__listOfMoveLabels.itemDoubleClicked.connect(
            self.moveDoubleClicked)

        # Build the vertical layout with the different widgets
        self.__layout.addWidget(self.__nameLabel)
        self.__layout.addWidget(self.nameEntry)
        self.__layout.addWidget(self.__listOfMoveLabels)
        for motorNumber in range(len(self.__motors)):
            self.__layout.addWidget(self.__motorLabels[motorNumber])
            self.__layout.addWidget(self.listOfSliders[motorNumber])
        self.__layout.addWidget(self.nextMoveButton)
        self.__layout.addWidget(self.buttonBox)

        # Connect the qwidgetlist to the custom right click menu
        self.__listOfMoveLabels.setContextMenuPolicy(Qt.CustomContextMenu)
        self.__listOfMoveLabels.customContextMenuRequested.connect(
            self.rightClickMenu)

    def setName(self, name):
        """
        Sets the name of the sequence with the user input
        :param name: The name of the sequence
        :return: No return
        """
        self.__sequence.setName(name)

    def getSequence(self):
        """
        Accessor of the sequence (for tests)
        :return: the sequence
        """
        return self.__sequence

    def getListofMoveLabels(self):
        """
        Accessor of the list of move labels (for tests)
        :return: the list of move labels
        """
        return self.__listOfMoveLabels

    def addSequenceToList(self, modifySequence=False):
        """
        Add the sequence to the list of sequence
        :param modifySequence: bool, if true there's a selected sequence that needs to be modified if false
        it's a new sequence
        :return: No return
        """
        # TODO: look to move this method to the list of sequence handler
        # TODO: don't let the user enter a sequence that has the same name as an old one
        self.setName(self.nameEntry.text())
        if self.__sequence.getName() != "":
            # Load previously saved sequences
            try:
                with open('SaveSequence.json') as save:
                    savedListOfSequences = json.load(save)
            except FileNotFoundError:
                savedListOfSequences = []

            if modifySequence:
                # Get the item that needs to be modified
                # selectedSequence = self.__listOfSequenceHandler.getSelectedItems()
                # Find the selected sequence in the list of saved ones
                for sequence in savedListOfSequences:
                    if self.__sequence.getName() in sequence:
                        indexOfTheSequence = savedListOfSequences.index(
                            sequence)
                        # remove the unmodified sequence to insert the modified sequence
                        savedListOfSequences.remove(sequence)
                        self.__listOfSequenceHandler.addItem(self.__sequence)
                        # Make the sequence json seriable
                        newSequence = dict()
                        newSequence[self.__sequence.getName()] = []
                        for moveNumber in range(len(
                                self.__sequence.getMoves())):
                            newSequence[self.__sequence.getName()].append(
                                self.__sequence.getMoves()
                                [moveNumber].getMovePositions())

                        # Append new sequence to the old ones
                        savedListOfSequences.insert(indexOfTheSequence,
                                                    newSequence)

                        # Write the sequences to the file
                        with open('SaveSequence.json', 'w') as outfile:
                            json.dump(savedListOfSequences, outfile)

                        self.accept()
            else:
                self.__listOfSequenceHandler.addItem(self.__sequence)
                # Make the sequence json seriable
                newSequence = dict()
                newSequence[self.__sequence.getName()] = []
                for moveNumber in range(len(self.__sequence.getMoves())):
                    newSequence[self.__sequence.getName()].append(
                        self.__sequence.getMoves()
                        [moveNumber].getMovePositions())

                # Append new sequence to the old ones
                savedListOfSequences.append(newSequence)

                # Write the sequences to the file
                with open('SaveSequence.json', 'w') as outfile:
                    json.dump(savedListOfSequences, outfile)

                self.accept()
        else:
            self.setEnabled(False)
            self.__noNameMessage.exec_()

    def addMovetoSequence(self):
        """
        Add the last move to the sequence
        :return: No return
        """
        move = None
        labelToModify = None
        # Check if there's a move in modifying state
        for row in range(self.__listOfMoveLabels.count()):
            if not self.__listOfMoveLabels.item(row).getMove().isNew:
                move = self.__listOfMoveLabels.item(row).getMove()
                labelToModify = self.__listOfMoveLabels.item(row)
                break
        # verify if the move is a new one
        if move is None:
            # Create the new move and set his positions
            move = Move(self.__motors)
            i = 0
            for motorName in self.__motors:
                move.setMotorPosition(motorName, self.listOfSliders[i].value())
                i += 1
            self.__sequence.addMove(move)

            # Set text for the move label
            labelText = "move " + str(
                self.__sequence.getNumberofMoves()) + ": "
            i = 0
            for motor in self.__motors:
                labelText += self.__motors[motor].getName() + " " +\
                             str(self.listOfSliders[i].value()) + ", "
                i += 1
            label = moveLabel(move, labelText, self.__motors)

            # insert label to the head of the list
            self.__listOfMoveLabels.insertItem(0, label)
        else:
            # modify the move
            i = 0
            for motorName in self.__motors:
                move.setMotorPosition(motorName, self.listOfSliders[i].value())
                i += 1

            # modify the label of the move
            textToEdit = labelToModify.text()
            listOfTextToEdit = textToEdit.split(' ')
            labelText = listOfTextToEdit[0] + " " + listOfTextToEdit[1] + " "
            i = 0
            for motor in self.__motors:
                labelText += self.__motors[motor].getName() + " " + \
                             str(self.listOfSliders[i].value()) + ", "
                i += 1
            labelToModify.setText(labelText)
            labelToModify.setSelected(False)
            labelToModify.setBackground(Qt.white)

            # reset the state of the move
            move.isNew = True

    # Access the move positions when double clicked on
    def moveDoubleClicked(self, moveItem):
        """
        Called when a move in the sequence is double clicked
        :param moveItem: the move that was double clicked
        :return: No return
        """
        moveItem.goToMoveOfTheLabel()
        self.updateSlidersPositions()

    def updateSlidersPositions(self):
        counterMotors = 0
        for motor in self.__motors:
            self.listOfSliders[counterMotors].setValue(
                self.__motors[motor].getGoalPosition())
            counterMotors += 1

    def enableWindow(self):
        """
        Enable the create sequence window
        :return:
        """
        self.setEnabled(True)

    def rightClickMenu(self, event):
        """
        The right click menu of the move list
        :param event: The event (here right click) that makes the menu come up
        :return: No return
        """
        menu = QMenu()
        # Add a button in the menu that when clicked, it puts a move in modifying state
        menu.addAction(
            "Modify Move", lambda: self.modifyMove(self.__listOfMoveLabels.
                                                   selectedItems()[0]))
        # Add a button in the menu that when clicked, it deletes a move in the list
        menu.addAction(
            "Delete Move", lambda: self.deleteMove(self.__listOfMoveLabels.
                                                   selectedItems()[0]))
        menu.exec_(self.__listOfMoveLabels.mapToGlobal(event))

    def deleteMove(self, label):
        """
        Delete a move and its label of the sequence
        :param label: label of the move
        :return: No return
        """
        # remove the label from the list
        self.__listOfMoveLabels.takeItem(self.__listOfMoveLabels.row(label))
        # remove the move from the sequence
        self.__sequence.deleteMove(label.getMove())

        # rename the labels in the list of moves
        for index in range(self.__sequence.getNumberofMoves() - 1, -1, -1):
            labelToModify = self.__listOfMoveLabels.item(index)
            textToEdit = labelToModify.text()
            listOfTextToEdit = textToEdit.split(' ')
            listOfTextToEdit[1] = str(self.__sequence.getNumberofMoves() -
                                      index) + ':'
            textToEdit = ' '.join(listOfTextToEdit)
            self.__listOfMoveLabels.item(index).setText(textToEdit)

    def modifyMove(self, label):
        """
        Put a move to a modified state
        :param label: label of the move
        :return: No return
        """
        # Check if there's a move in modifying state
        for row in range(self.__listOfMoveLabels.count()):
            if not self.__listOfMoveLabels.item(row).getMove().isNew:
                self.__listOfMoveLabels.item(row).getMove().isNew = True
                self.__listOfMoveLabels.item(row).setBackground(
                    QBrush(Qt.white))

        moveToModify = label.getMove()
        moveToModify.isNew = False
        label.setBackground(QBrush(Qt.darkCyan))
        label.goToMoveOfTheLabel()
        self.updateSlidersPositions()
Example #26
0
class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Network Designer")
        self.setGeometry(300, 200, 840, 720)
        self.current_id = 1
        self.createLayout()

        self.couple = []
        self.show()

    def makeButtonsLayout(self):
        self.button = QPushButton("Add Node", self)
        self.button.clicked.connect(self.addNode)

        self.btn_connection = QPushButton("Add Connection:", self)
        self.btn_connection.clicked.connect(self.addConnection)

        self.button3 = QPushButton("Export Network", self)
        self.button3.clicked.connect(self.file_save)

        self.lbl_connection = QLabel("Connection")

        self.l_btns = QHBoxLayout()
        self.l_btns.addWidget(self.button3)
        self.l_btns.addStretch()
        self.l_btns.addWidget(self.btn_connection)
        self.l_btns.addWidget(self.lbl_connection)
        self.l_btns.addStretch()
        self.l_btns.addWidget(self.button)
        self.btns = QWidget()
        self.btns.setLayout(self.l_btns)
        self.btns.setFixedHeight(40)

    def initializeGview(self):
        self.scene = GraphicsScene()
        self.scene.setSceneRect(0, 0, 480, 480)
        self.scene.click.connect(self.keepNode)
        self.addNode()
        self.view = QGraphicsView(self.scene)
        self.view.setGeometry(0, 0, 500, 500)
        self.view.scale(1, 1)

    def createOrderList(self):
        self.orderList = QListWidget()
        # Enable drag & drop ordering of items.
        self.orderList.setDragDropMode(QAbstractItemView.InternalMove)

    def createLayout(self):
        self.makeButtonsLayout()
        self.initializeGview()
        self.createOrderList()

        l_network = QHBoxLayout()
        l_network.addWidget(self.view)
        l_network.addStretch()
        l_network.addWidget(self.orderList)

        self.l_root = QVBoxLayout()
        self.l_root.addLayout(l_network)
        self.l_root.addStretch()
        self.l_root.addWidget(self.btns)

        # self.l_root.addWidget(self.view)
        self.setLayout(self.l_root)

    def addNode(self):
        greenBrush = QBrush(Qt.green)
        blackPen = QPen(Qt.black)
        # blueBrush = QBrush(Qt.blue)

        blackPen.setWidth(5)
        ellipse = GraphicsEllipse(str(self.current_id), blackPen, greenBrush, 100, 100, NODE_D, NODE_D)
        self.scene.addItem(ellipse)
        self.current_id += 1

    def keepNode(self, node):
        if len(self.couple) < 2:
            self.couple.append(node)
        else:
            self.couple.pop(0)
            self.couple.append(node)
        if len(self.couple) == 2:
            self.lbl_connection.setText(self.couple[0].label + " --> " + self.couple[1].label)

    def addConnection(self):
        line = GraphicsLine(self.couple[0], self.couple[1], NODE_R)
        self.scene.addItem(line)

        for v in self.couple:
            v.add_connection(line)
        self.orderList.addItem(self.lbl_connection.text())

    def getNodes(self):
        positions = {}
        for i in self.scene.items():
            if type(i) is GraphicsEllipse:
                positions[int(i.label)] = i.getPosition()
        return positions

    def getConnections(self):
        connections = []
        for i in range(self.orderList.count()):
            conn = self.orderList.item(i).text().split(" --> ")
            connections.append((int(conn[0]), int(conn[1]), {"label": str(i + 1)}))
        return connections

    def file_save(self):
        positions = self.getNodes()
        connections = self.getConnections()
        network = {}
        network["labels"] = {i: i for i in sorted(list(positions.keys()))}
        network["edges"] = connections
        network["pos"] = positions
        text = json.dumps(network)
        name = QFileDialog.getSaveFileName(self, 'Save File')
        file = open(name[0], 'w')
        # text = "something"
        file.write(text)
        file.close()
Example #27
0
class SynthPdfWidget(QWidget):
    def __init__(self, status_bar):
        super(SynthPdfWidget, self).__init__()
        self.status_bar = status_bar
        layout = QHBoxLayout()
        self.list_view = QListWidget()
        self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_view.setAlternatingRowColors(True)
        self.list_view.itemClicked.connect(self.click_item_signal)
        self.list_view.itemEntered.connect(self.click_item_signal)
        self.list_view.itemSelectionChanged.connect(
            self.change_selection_signal)

        controls_layout = QVBoxLayout()
        controls_layout.setAlignment(Qt.AlignTop)

        select_zone = SelectWidget(self.click_move_up, self.click_move_down,
                                   self.click_invert, self.click_delete)
        select_zone.setMinimumWidth(250)

        add_pages_button = QPushButton("Add Pages From PDF")
        add_pages_button.clicked.connect(self.add_pdf)

        controls_layout.addWidget(select_zone)
        controls_layout.addWidget(add_pages_button)

        layout.addWidget(self.list_view)
        layout.addLayout(controls_layout)
        self.setLayout(layout)

    def _add_pages_from_pdf(self, pdf_path):
        with open(pdf_path, "rb") as file:
            reader = PdfFileReader(file)
            file_name = os.path.basename(pdf_path)
            pages_count = reader.getNumPages()
            for i in range(pages_count):
                new_item = ImageListItem(
                    "page " + str(i + 1) + " (" + file_name + ")",
                    (pdf_path, i))
                self.list_view.addItem(new_item)
            self.status_bar.showMessage("Add " + str(pages_count) + " pages")

    # ----------external methods from create command
    def extern_get_files_and_pages(
        self
    ):  # return selected pages in the form {file1: [p1, p2, ...], file2: [p1, p2, ...], ...}
        to_return = {}
        if len(self.list_view.selectedItems()
               ) == 0:  # nothing selected, add all pages
            items_count = self.list_view.count()
            for item_index in range(items_count):
                item = self.list_view.item(item_index)
                item_data = item.get_data()
                file_name = item_data[0]
                page_index = item_data[1]
                if file_name in to_return:
                    to_return[file_name].append(page_index)
                else:
                    to_return[file_name] = [page_index]
        else:
            for s in self.list_view.selectedItems():
                s_data = s.get_data()
                file_name = s_data[0]
                page_index = s_data[1]
                if file_name in to_return:
                    to_return[file_name].append(page_index)
                else:
                    to_return[file_name] = [page_index]
        return to_return

    # ----------add button-----------------------
    def add_pdf(self):
        files_dialog = QFileDialog()
        files_dialog.setNameFilter("PDF (*.pdf)")
        files_dialog.setFileMode(QFileDialog.ExistingFiles)
        if files_dialog.exec_():
            files = files_dialog.selectedFiles()
            for f_path in files:
                self._add_pages_from_pdf(f_path)

    # ----------List_view signals----------------
    def click_item_signal(self, item):
        self.status_bar.showMessage("Select " + str(item.text()))

    def change_selection_signal(self):
        if len(self.list_view.selectedItems()) == 0:
            # self._set_preview(None)  # nothing selected
            pass

    # ----------list_view commands---------------
    def click_move_up(self):
        selected = self.list_view.selectedItems()
        selected_indexes = [
            self.list_view.indexFromItem(sel).row() for sel in selected
        ]
        selected_indexes.sort()
        if len(selected_indexes) > 0 and selected_indexes[0] > 0:
            for index in selected_indexes:
                prev_item = self.list_view.takeItem(index - 1)
                self.list_view.insertItem(index, prev_item)
            self.status_bar.showMessage("Move " + str(len(selected_indexes)) +
                                        " items")
        else:
            self.status_bar.showMessage("Nothing to move")

    def click_move_down(self):
        selected = self.list_view.selectedItems()
        selected_indexes = [
            self.list_view.indexFromItem(sel).row() for sel in selected
        ]
        selected_indexes.sort()
        sel_count = len(selected_indexes)
        if len(selected_indexes) > 0 and selected_indexes[
                sel_count - 1] < self.list_view.count() - 1:
            for i_index in range(sel_count):
                next_item = self.list_view.takeItem(
                    selected_indexes[sel_count - i_index - 1] + 1)
                self.list_view.insertItem(
                    selected_indexes[sel_count - i_index - 1], next_item)
            self.status_bar.showMessage("Move " + str(len(selected_indexes)) +
                                        " items")
        else:
            self.status_bar.showMessage("Nothing to move")

    def click_invert(self):
        selected = self.list_view.selectedItems()
        selected_indexes = []
        for sel in selected:
            selected_indexes.append(self.list_view.indexFromItem(sel).row())
        total_indexes = [i for i in range(self.list_view.count())]
        new_indexes = []
        for i in total_indexes:
            if i not in selected_indexes:
                new_indexes.append(i)
        self.list_view.clearSelection()
        for i in new_indexes:
            self.list_view.item(i).setSelected(True)
        self.status_bar.showMessage("Invert selection: " + str(new_indexes))

    def click_delete(self):
        selected = self.list_view.selectedItems()
        delete_names = []
        for s in selected:
            s_index = self.list_view.indexFromItem(s).row()
            del_item = self.list_view.takeItem(s_index)
            delete_names.append(del_item.text())
        if len(delete_names) == 0:
            self.status_bar.showMessage("Nothing to delete")
        else:
            self.status_bar.showMessage("Delete items: " +
                                        ", ".join(delete_names))
Example #28
0
class ImageToPdfWidget(QWidget):
    def __init__(self, status_link):
        super(ImageToPdfWidget, self).__init__()
        LABEL_WIDTH = 80
        self.last_selected_items = []
        self.options_mode = 0
        self.update_status_combobox = False
        layout = QHBoxLayout()
        self.status_bar = status_link
        self.list_view = QListWidget()
        self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_view.setAlternatingRowColors(True)
        self.list_view.itemClicked.connect(self.click_item_signal)
        self.list_view.itemEntered.connect(self.click_item_signal)
        self.list_view.itemSelectionChanged.connect(
            self.change_selection_signal)

        controls_layout = QVBoxLayout()
        controls_layout.setAlignment(Qt.AlignTop)

        select_zone = SelectWidget(self.click_move_up, self.click_move_down,
                                   self.click_invert, self.click_delete)

        # options zone -------------------------------------
        options_zone = QGroupBox("Options")
        self.options_zone_layout = QVBoxLayout()

        self.options_mode_combobox = QComboBox()
        self._add_items_to_mode_combobox(self.options_mode_combobox)
        options_mode_label = QLabel("Mode")
        options_mode_label.setMaximumWidth(LABEL_WIDTH)
        options_mode_layout = QHBoxLayout()
        options_mode_layout.addWidget(options_mode_label)
        options_mode_layout.addWidget(self.options_mode_combobox)
        self.options_zone_layout.addLayout(options_mode_layout)
        self.option_source_widget = OptionsFromSourceWidget(
            label_width=LABEL_WIDTH, status_bar=self.status_bar)
        self.options_a_widget = OptionsAWidget(label_width=LABEL_WIDTH,
                                               status_bar=self.status_bar)
        self.options_mode_combobox.currentIndexChanged.connect(
            self.change_options_mode_signal)
        self.change_options_mode_signal(self.options_mode)

        options_zone.setLayout(self.options_zone_layout)

        # Add files button and final structures ---------------------------
        add_file_button = QPushButton("Add Files")
        add_file_button.clicked.connect(self.click_add_files)
        controls_layout.addWidget(select_zone)
        controls_layout.addWidget(options_zone)
        controls_layout.addWidget(add_file_button)

        # image preview ---------------------------------------------------
        image_prev_layout = QVBoxLayout()
        image_prev_layout.setContentsMargins(0, 0, 4, 0)
        self.IMG_PREVIEW_WIDTH = 256
        self.img_label = QLabel()
        self.img_label.setAlignment(Qt.AlignCenter)
        self.select_text = "Click item to preview"
        self.last_created_pix_path = ""
        self.img_label.setText(self.select_text)
        image_prev_layout.addWidget(self.img_label)
        # slider for the preview scale
        self.img_scale_slider = QSlider()
        self.img_scale_slider.setMinimum(6)
        self.img_scale_slider.setMaximum(2048)
        self.img_scale_slider.setValue(self.IMG_PREVIEW_WIDTH)
        self.img_scale_slider.setOrientation(Qt.Horizontal)
        self.img_scale_slider.valueChanged.connect(
            self.change_scale_slider_signal)
        image_prev_layout.addWidget(self.img_scale_slider)
        self._update_preview()

        layout.addLayout(image_prev_layout)
        layout.addWidget(self.list_view)
        layout.addLayout(controls_layout)
        self.setLayout(layout)
        self.update_status_combobox = True

    def _pillow_to_pixmap(self, img):
        if img.mode == "RGB":
            r, g, b = img.split()
            img = Image.merge("RGB", (b, g, r))
        elif img.mode == "RGBA":
            r, g, b, a = img.split()
            img = Image.merge("RGBA", (b, g, r, a))
        elif img.mode == "L":
            img = img.convert("RGBA")
        img2 = img.convert("RGBA")
        data = img2.tobytes("raw", "RGBA")
        qim = QImage(data, img.size[0], img.size[1], QImage.Format_ARGB32)
        pixmap = QPixmap.fromImage(qim)
        return pixmap

    def _update_preview(self):
        self.img_label.setMinimumWidth(self.IMG_PREVIEW_WIDTH)
        self.img_label.setMaximumWidth(
            max(self.IMG_PREVIEW_WIDTH, self.img_scale_slider.width()))
        if len(self.last_created_pix_path) > 0:
            img = Image.open(self.last_created_pix_path)
            img_pix = self._pillow_to_pixmap(img)
            img_pix = img_pix.scaled(
                QSize(self.IMG_PREVIEW_WIDTH, self.IMG_PREVIEW_WIDTH),
                Qt.KeepAspectRatio)
            self.img_label.setPixmap(img_pix)

    def _set_preview(self, img_path):
        if img_path is None:
            self.last_created_pix_path = ""
            self.img_label.setText(self.select_text)
        else:
            if img_path != self.last_created_pix_path:
                self.last_created_pix_path = img_path
                self._update_preview()

    def _add_items_to_mode_combobox(self, combobox):
        combobox.addItem("From Source")
        combobox.addItem("A4")
        # combobox.addItem("A5")
        # combobox.addItem("A6")
        # combobox.addItem("Letter")

    def _get_filtered_string(self, string):
        to_return_array = []
        for s in string:
            if s.isdigit():
                to_return_array.append(s)
        return "".join(to_return_array)

    def get_images_to_save(self):
        path_array = []
        for i in range(self.list_view.count()):
            path_array.append(self.list_view.item(i).get_data())
        return path_array

    def get_image_parameters(self):  # return as dictionary
        if self.options_mode == 0:
            return {
                "mode": 0,
                "pixels": self.option_source_widget.get_pixel_value(),
                "margin": self.option_source_widget.get_margin_value(),
                "background": self.option_source_widget.get_background_value()
            }
        else:
            return {
                "mode": self.options_mode,
                "align": self.options_a_widget.get_align_value(),
                "margin": self.options_a_widget.get_margin_value(),
                "background": self.options_a_widget.get_background_value()
            }

    def add_items(self, array):
        added_names = []
        for a in array:
            new_name = os.path.basename(a)
            new_item = ImageListItem(new_name, a)
            added_names.append(new_name)
            self.list_view.addItem(new_item)
        self.status_bar.showMessage("Add items: " + ", ".join(added_names))

    def change_scale_slider_signal(self, value):
        self.IMG_PREVIEW_WIDTH = value
        self._update_preview()
        self.status_bar.showMessage("Set preview scale to " + str(value))

    def click_item_signal(self, item):
        pass
        # self._set_preview(item.get_data())
        # self.status_bar.showMessage("Select " + str(item.text()))

    def _get_first_new_index(self, current, last):
        for v in current:
            if v not in last:
                return v
        return current[0]

    def change_selection_signal(self):
        if len(self.list_view.selectedItems()) == 0:
            self._set_preview(None)  # nothing selected
        else:
            selected_indexes = [
                self.list_view.indexFromItem(sel).row()
                for sel in self.list_view.selectedItems()
            ]
            item = self.list_view.item(
                self._get_first_new_index(selected_indexes,
                                          self.last_selected_items))
            self._set_preview(item.get_data())
            self.status_bar.showMessage("Select " + str(item.text()))
            self.last_selected_items = selected_indexes

    def change_options_mode_signal(self, index):
        self.options_mode = index
        if self.options_mode == 0:
            self.options_zone_layout.removeWidget(self.options_a_widget)
            self.options_a_widget.setParent(None)
            self.options_zone_layout.addWidget(self.option_source_widget)
        else:
            self.options_zone_layout.removeWidget(self.option_source_widget)
            self.option_source_widget.setParent(None)
            self.options_zone_layout.addWidget(self.options_a_widget)
        if self.update_status_combobox:
            self.status_bar.showMessage(
                "Set combine mode to \"" +
                self.options_mode_combobox.itemText(index) + "\"")

    def resizeEvent(self, size):
        # self._update_preview()
        pass

    def click_move_up(self):
        selected = self.list_view.selectedItems()
        selected_indexes = [
            self.list_view.indexFromItem(sel).row() for sel in selected
        ]
        selected_indexes.sort()
        if len(selected_indexes) > 0 and selected_indexes[0] > 0:
            for index in selected_indexes:
                prev_item = self.list_view.takeItem(index - 1)
                self.list_view.insertItem(index, prev_item)
            self.status_bar.showMessage("Move " + str(len(selected_indexes)) +
                                        " items")
        else:
            self.status_bar.showMessage("Nothing to move")

    def click_move_down(self):
        selected = self.list_view.selectedItems()
        selected_indexes = [
            self.list_view.indexFromItem(sel).row() for sel in selected
        ]
        selected_indexes.sort()
        sel_count = len(selected_indexes)
        if len(selected_indexes) > 0 and selected_indexes[
                sel_count - 1] < self.list_view.count() - 1:
            for i_index in range(sel_count):
                next_item = self.list_view.takeItem(
                    selected_indexes[sel_count - i_index - 1] + 1)
                self.list_view.insertItem(
                    selected_indexes[sel_count - i_index - 1], next_item)
            self.status_bar.showMessage("Move " + str(len(selected_indexes)) +
                                        " items")
        else:
            self.status_bar.showMessage("Nothing to move")

    def click_invert(self):
        selected = self.list_view.selectedItems()
        selected_indexes = []
        for sel in selected:
            selected_indexes.append(self.list_view.indexFromItem(sel).row())
        total_indexes = [i for i in range(self.list_view.count())]
        new_indexes = []
        for i in total_indexes:
            if i not in selected_indexes:
                new_indexes.append(i)
        self.list_view.clearSelection()
        for i in new_indexes:
            self.list_view.item(i).setSelected(True)
        self.status_bar.showMessage("Invert selection: " + str(new_indexes))

    def click_delete(self):
        selected = self.list_view.selectedItems()
        delete_names = []
        for s in selected:
            s_index = self.list_view.indexFromItem(s).row()
            del_item = self.list_view.takeItem(s_index)
            delete_names.append(del_item.text())
        if len(delete_names) == 0:
            self.status_bar.showMessage("Nothing to delete")
        else:
            self.status_bar.showMessage("Delete items: " +
                                        ", ".join(delete_names))

    def click_add_files(self):
        files_dialog = QFileDialog()
        files_dialog.setNameFilter("Images (*.jpg *.jpeg *.bmp *.png *.tiff)")
        files_dialog.setFileMode(QFileDialog.ExistingFiles)
        if files_dialog.exec_():
            files = files_dialog.selectedFiles()
            self.add_items(files)
Example #29
0
class FieldAttrsDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setLayout(QGridLayout())
        self.setWindowTitle("Edit Attributes")

        self.list_widget = QListWidget()
        self.list_widget.setMinimumSize(800, 600)
        self.add_button = QPushButton("Add attr")
        self.add_button.clicked.connect(self.__add_attr)
        self.remove_button = QPushButton("Remove attr")
        self.remove_button.clicked.connect(self._remove_attrs)

        self.layout().addWidget(self.list_widget, 0, 0, 2, 1)
        self.layout().addWidget(self.add_button, 0, 1)
        self.layout().addWidget(self.remove_button, 1, 1)

    def fill_existing_attrs(self, existing_dataset: Dataset):
        for attr in existing_dataset.attributes:
            if attr.name not in ATTRS_EXCLUDELIST:
                frame = FieldAttrFrame(attr)
                self._add_attr(existing_frame=frame)

    def __add_attr(self):
        """
        Only used for button presses. Any additional arguments from the signal are ignored.
        """
        self._add_attr()

    def _add_attr(self, existing_frame=None):
        item = QListWidgetItem()
        self.list_widget.addItem(item)
        frame = existing_frame if existing_frame is not None else FieldAttrFrame(
        )
        item.setSizeHint(frame.sizeHint())
        self._setup_attribute_name_validator(frame)
        self.list_widget.setItemWidget(item, frame)

    def _remove_attrs(self):
        for index in self.list_widget.selectedIndexes():
            self.list_widget.takeItem(index.row())

    def get_attrs(self):
        attrs_list = []
        for index in range(self.list_widget.count()):
            item = self.list_widget.item(index)
            widget = self.list_widget.itemWidget(item)
            if widget:
                attrs_list.append((widget.name, widget.value, widget.dtype))
        return attrs_list

    def get_attr_names(self):
        return [item[0] for item in self.get_attrs()]

    def _setup_attribute_name_validator(self, frame):
        frame.attr_name_lineedit.setValidator(
            AttributeNameValidator(self.get_attr_names))
        frame.attr_name_lineedit.validator().is_valid.connect(
            partial(
                validate_line_edit,
                frame.attr_name_lineedit,
                tooltip_on_accept="Attribute name is valid.",
                tooltip_on_reject="Attribute name is not valid",
            ))
Example #30
0
class VODCutter(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.twitch_client_id = config.TWITCH_API_CLIENT_ID
        self.twitch_oauth_token = config.TWITCH_API_OAUTH_TOKEN

        self.twitch_interface = TwitchInterface(
            api_client_id=config.TWITCH_API_CLIENT_ID,
            api_oauth_token=config.TWITCH_API_OAUTH_TOKEN,
            browser_client_id=config.TWITCH_BROWSER_OAUTH_TOKEN,
            browser_oauth_token=config.TWITCH_BROWSER_OAUTH_TOKEN)

        self.vlc_interface = VLCInterface(config.VLC_PATH)

        self.loaded_video = None

        self.main_layout = QVBoxLayout()

        self.launch_vlc_btn = QPushButton("Launch VLC")

        self.info_layout = QGridLayout()

        self.file_picker_layout = QHBoxLayout()

        self.file_path_field = QLineEdit()
        self.file_browser_btn = QPushButton(text="...")

        self.file_picker_layout.addWidget(self.file_path_field)
        self.file_picker_layout.addWidget(self.file_browser_btn)

        vod_filepath_label = QLabel("VOD Filepath")
        id_twitch_label = QLabel("ID Twitch")
        created_at_label = QLabel("Created at")
        duration_label = QLabel("Duration")
        title_label = QLabel("Title")
        streamer_label = QLabel("Streamer")

        self.id_twitch_field = QLineEdit()
        self.created_at_field = QLineEdit()
        self.duration_field = QLineEdit()
        self.title_field = QLineEdit()
        self.streamer_field = QLineEdit()

        self.id_twitch_field.setEnabled(False)
        self.created_at_field.setEnabled(False)
        self.duration_field.setEnabled(False)
        self.title_field.setEnabled(False)
        self.streamer_field.setEnabled(False)

        self.info_layout.addWidget(vod_filepath_label, 0, 0)
        self.info_layout.addWidget(id_twitch_label, 1, 0)
        self.info_layout.addWidget(created_at_label, 2, 0)
        self.info_layout.addWidget(duration_label, 3, 0)
        self.info_layout.addWidget(title_label, 4, 0)
        self.info_layout.addWidget(streamer_label, 5, 0)

        self.info_layout.addLayout(self.file_picker_layout, 0, 1)
        self.info_layout.addWidget(self.id_twitch_field, 1, 1)
        self.info_layout.addWidget(self.created_at_field, 2, 1)
        self.info_layout.addWidget(self.duration_field, 3, 1)
        self.info_layout.addWidget(self.title_field, 4, 1)
        self.info_layout.addWidget(self.streamer_field, 5, 1)

        self.segments_create_btn = QPushButton("Import Chapters")
        self.download_thumbnails_btn = QPushButton("Download Thumbnails")
        self.download_chatlog_btn = QPushButton("Download Chat Log")

        self.segments_list = QListWidget()

        self.segments_add_btn = QPushButton(text="+")
        self.segments_delete_btn = QPushButton(text="-")

        self.jump_start_btn = QPushButton(text="Jump To Start")
        self.jump_end_btn = QPushButton(text="Jump To End")

        self.set_start_btn = QPushButton(text="Set Start")
        self.set_end_btn = QPushButton(text="Set End")

        self.split_btn = QPushButton(text="Split")

        self.process_selected_btn = QPushButton(
            text="Process Selected Segment")
        self.process_all_btn = QPushButton(text="Process All Segments")

        self.jump_layout = QHBoxLayout()

        self.jump_layout.addWidget(self.jump_start_btn)
        self.jump_layout.addWidget(self.jump_end_btn)

        self.set_layout = QHBoxLayout()

        self.set_layout.addWidget(self.set_start_btn)
        self.set_layout.addWidget(self.set_end_btn)

        self.main_layout.addWidget(self.launch_vlc_btn)
        self.main_layout.addLayout(self.file_picker_layout)
        self.main_layout.addLayout(self.info_layout)
        self.main_layout.addWidget(self.segments_create_btn)
        self.main_layout.addWidget(self.download_thumbnails_btn)
        self.main_layout.addWidget(self.download_chatlog_btn)
        self.main_layout.addWidget(self.segments_list)
        self.main_layout.addWidget(self.segments_add_btn)
        self.main_layout.addWidget(self.segments_delete_btn)
        self.main_layout.addLayout(self.jump_layout)
        self.main_layout.addLayout(self.set_layout)
        self.main_layout.addWidget(self.split_btn)
        self.main_layout.addWidget(self.process_selected_btn)
        self.main_layout.addWidget(self.process_all_btn)

        self.main_widget = QWidget()
        self.main_widget.setLayout(self.main_layout)

        self.setCentralWidget(self.main_widget)

        self.segments_list.itemDoubleClicked.connect(
            self.on_segments_list_doubleclick)

        self.jump_start_btn.clicked.connect(self.jump_to_segment_start)
        self.jump_end_btn.clicked.connect(self.jump_to_segment_end)
        self.set_start_btn.clicked.connect(self.set_segment_start)
        self.set_end_btn.clicked.connect(self.set_segment_end)

        self.download_thumbnails_btn.clicked.connect(self.download_thumbnails)
        self.segments_add_btn.clicked.connect(self.create_segment)
        self.segments_delete_btn.clicked.connect(self.delete_segment)
        self.split_btn.clicked.connect(self.split_selected_segment)
        self.launch_vlc_btn.clicked.connect(self.on_launch_vlc)
        self.file_path_field.returnPressed.connect(self.on_video_url_changed)
        self.file_browser_btn.clicked.connect(self.on_filebrowse_btn_click)
        self.process_selected_btn.clicked.connect(
            self.process_selected_segment)
        self.process_all_btn.clicked.connect(self.process_all_segments)

    def on_launch_vlc(self):
        self.vlc_interface.launch()

    def on_filebrowse_btn_click(self):
        filename = QFileDialog.getOpenFileName(self, "Select a video file")
        if filename[0]:
            self.set_video_file(filename[0])

    def on_video_url_changed(self):
        self.set_video_file(self.file_path_field.text())

    def on_segments_list_doubleclick(self, item):
        current_segment = item.get_segment()
        if current_segment:
            self.vlc_interface.set_current_time(int(
                current_segment.start_time))

    def set_video_file(self, filepath=None):
        self.file_path_field.setText("" if filepath is None else filepath)

        if filepath:
            self.loaded_video = InputVideo()

            if re.search(r"^(?:/|[a-z]:[\\/])", filepath, re.I):
                file_url = "file://" + filepath
                self.loaded_video.is_local = True
            else:
                file_url = filepath

            if not self.loaded_video.is_local:
                streams = streamlink.streams(file_url)
                if streams:
                    self.loaded_video.filepath = streams["best"].url
                else:
                    self.loaded_video.filepath = file_url
            else:
                self.loaded_video.filepath = file_url

            try:
                self.update_twitch_metadatas()
            except requests.exceptions.ConnectionError:
                print("<!!> Can't connect to Twitch API.")

            try:
                self.vlc_interface.open_url(self.loaded_video.filepath)
            except requests.exceptions.ConnectionError:
                print("<!!> Can't connect to local VLC instance.")

    def get_twitch_id_from_filepath(self):
        filename = self.file_path_field.text()

        parsed_filename = re.search("([0-9]+)\.mp4$", filename, re.I)

        if parsed_filename:
            video_id = parsed_filename.group(1)
            return int(video_id)
        else:
            parsed_url = re.search("videos/([0-9]+)", filename, re.I)
            if parsed_url:
                video_id = parsed_url.group(1)
                return int(video_id)
            else:
                raise Exception(
                    f"<!!> Can't find video Twitch id in video filename ({filename})"
                )

    def create_segment_before(self, segment_obj):
        pass

    def create_segment_after(self, segment_obj):
        pass

    def update_twitch_metadatas(self):
        twitch_video_id = self.get_twitch_id_from_filepath()
        metadatas = self.twitch_interface.get_twitch_metadatas(twitch_video_id)

        self.loaded_video.metadatas = metadatas

        duration = parse_duration(metadatas["duration"])

        self.id_twitch_field.setText(metadatas["id"])
        self.created_at_field.setText(str(metadatas["created_at"]))
        self.duration_field.setText(format_time(duration.seconds))
        self.title_field.setText(metadatas["title"])
        self.streamer_field.setText(metadatas["user_login"])

        for moment in self.twitch_interface.get_video_games_list(
                metadatas["id"]):
            s = Segment()

            s.name = f"{moment['description']} ({moment['type']})"
            s.start_time = moment['positionMilliseconds'] / 1000
            s.end_time = (moment['positionMilliseconds'] +
                          moment['durationMilliseconds']) / 1000

            self.segments_list.addItem(SegmentListItem(s))

    def create_segment(self):
        s = Segment()

        s.name = f"Segment {self.segments_list.count()}"
        s.start_time = 0
        s.end_time = self.vlc_interface.get_duration()

        self.segments_list.addItem(SegmentListItem(s))

    def delete_segment(self):
        for item in self.segments_list.selectedItems():
            idx = self.segments_list.indexFromItem(item)
            item = self.segments_list.takeItem(idx.row())
            del item

    def split_selected_segment(self):
        current_time = self.vlc_interface.get_current_time()

        for segment_item in self.segments_list.selectedItems():
            current_segment = segment_item.get_segment()
            if current_segment:
                new_segment = segment_item.split(
                    current_time,
                    name="Splitted " + current_segment.name,
                    split_mode=SPLIT_MODE.ABSOLUTE)
                self.segments_list.addItem(SegmentListItem(new_segment))

    def get_selected_segments(self):
        return list(
            map(lambda item: item.get_segment(),
                self.segments_list.selectedItems()))

    def jump_to_segment_start(self):
        selected_segments = self.get_selected_segments()
        if selected_segments:
            self.vlc_interface.set_current_time(
                math.floor(selected_segments[0].start_time))

    def jump_to_segment_end(self):
        selected_segments = self.get_selected_segments()
        if selected_segments:
            self.vlc_interface.set_current_time(
                math.floor(selected_segments[0].end_time))

    def set_segment_start(self):
        current_time = self.vlc_interface.get_current_time()
        selected_segments = self.segments_list.selectedItems()
        if selected_segments:
            selected_segments[0].get_segment().start_time = current_time
            selected_segments[0].update()

    def set_segment_end(self):
        current_time = self.vlc_interface.get_current_time()
        selected_segments = self.segments_list.selectedItems()
        if selected_segments:
            selected_segments[0].get_segment().end_time = current_time
            selected_segments[0].update()

    def process_selected_segment(self):
        for segment in self.get_selected_segments():
            self.process_segment(segment)

    def process_all_segments(self):
        for idx in range(self.segments_list.count()):
            segment_item = self.segments_list.item(idx)
            self.process_segment(segment_item.get_segment())

    def process_segment(self, segment_obj):
        if not self.loaded_video:
            raise Exception("<!!> No video loaded")

        video_id = self.loaded_video.metadatas.get("id", None)
        created_at = self.loaded_video.metadatas.get("created_at", None)
        user_login = self.loaded_video.metadatas.get("user_login", None)

        if not (video_id and created_at and user_login):
            raise Exception("<!!> Missing video metadatas")

        created_at_timestamp = int(datetime.datetime.timestamp(created_at))

        if self.loaded_video.is_local:
            cmd = f'ffmpeg -i "{self.loaded_video.filepath}" -ss {segment_obj.start_time} -to {segment_obj.end_time} -c:v copy -c:a copy "{user_login}_{created_at_timestamp}_{video_id}.mp4"'
        else:
            cmd = f'streamlink -f --hls-start-offset {format_time(segment_obj.start_time)} --hls-duration {format_time(segment_obj.end_time - segment_obj.start_time)} --player-passthrough hls "{self.loaded_video.filepath}" best -o "{user_login}_{created_at_timestamp}_{video_id}.mp4"'

        print(cmd)

        os.system(cmd)

    def download_thumbnails(self):
        twitch_video_id_str = self.id_twitch_field.text()
        if twitch_video_id_str:
            thumbnails_manifest_url = self.twitch_interface.get_video_thumbnails_manifest_url(
                int(twitch_video_id_str))
            thumbnails_manifest, images_url_list = self.twitch_interface.get_thumbnails_url_from_manifest(
                thumbnails_manifest_url)

            for img in images_url_list:
                r = requests.get(images_url_list[img])
                fp = open(img, "wb")
                fp.write(r.content)
                fp.close()