class OLOverview(object):
    def __init__(self, iface, olLayerTypeRegistry):
        self._iface = iface
        self._olLayerTypeRegistry = olLayerTypeRegistry
        self._dockwidget = None
        self._oloWidget = None

    # Private
    def _setDocWidget(self):
        self._dockwidget = QDockWidget(
            QApplication.translate("OpenLayersOverviewWidget",
                                   "OpenLayers Overview"),
            self._iface.mainWindow())
        self._dockwidget.setObjectName("dwOpenlayersOverview")
        self._oloWidget = OpenLayersOverviewWidget(self._iface,
                                                   self._dockwidget,
                                                   self._olLayerTypeRegistry)
        self._dockwidget.setWidget(self._oloWidget)

    def _initGui(self):
        self._setDocWidget()
        # self._iface.addDockWidget(QtCore.LeftDockWidgetArea, self._dockwidget)
        self._iface.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
                                  self._dockwidget)

    def _unload(self):
        self._dockwidget.close()
        self._iface.removeDockWidget(self._dockwidget)
        del self._oloWidget
        self._dockwidget = None

    # Public
    def setVisible(self, visible):
        if visible:
            if self._dockwidget is None:
                self._initGui()
        else:
            if not self._dockwidget is None:
                self._unload()
Ejemplo n.º 2
0
class MainWindow(QMainWindow):
    """The main window."""
    def __init__(self, init_path=None):
        super(MainWindow, self).__init__()
        self.empty = False
        if init_path is None:
            # get initial path
            try:
                init_path = sys.argv[1]
            except IndexError:
                # show the icon image
                init_path = os.path.join(ROOT_DIR, 'icon.png')
                self.empty = True
        # initialize HVDB (handyview database), which stores the path info
        self.hvdb = HVDB(init_path)

        self.full_screen = False
        self.canvas_type = 'main'
        self.center_canvas = CenterWidget(self, self.hvdb)

        # initialize UI
        self.setWindowTitle('HandyView')
        self.init_menubar()
        self.init_toolbar()
        # self.init_statusbar()
        self.init_central_window()
        self.add_dock_window()

    def init_menubar(self):
        # create menubar
        menubar = self.menuBar()

        # File
        file_menu = menubar.addMenu('&File(文件)')
        file_menu.addAction(actions.open(self))
        file_menu.addAction(actions.history(self))
        file_menu.addSeparator()
        file_menu.addAction(actions.refresh(self))
        file_menu.addAction(actions.goto_index(self))
        file_menu.addSeparator()
        file_menu.addAction(actions.include_file_name(self))
        file_menu.addAction(actions.exclude_file_name(self))

        # Edit
        # edit_menu = menubar.addMenu('&Edit(编辑)')  # noqa: F841

        # Draw
        # draw_menu = menubar.addMenu('&Draw(画图)')  # noqa: F841

        # Compare
        compare_menu = menubar.addMenu('&Compare(比较)')
        compare_menu.addAction(actions.compare(self))
        compare_menu.addAction(actions.clear_compare(self))
        compare_menu.addAction(actions.set_fingerprint(self))

        # Layouts
        layout_menu = menubar.addMenu('&Layout(布局)')
        layout_menu.addAction(actions.switch_main_canvas(self))
        layout_menu.addAction(actions.switch_compare_canvas(self))
        layout_menu.addAction(actions.switch_preview_canvas(self))

        # Tabs
        layout_menu = menubar.addMenu('&Tabs(选项卡)')
        layout_menu.addAction(actions.select_basic_tab(self))
        layout_menu.addAction(actions.select_crop_tab(self))
        layout_menu.addAction(actions.select_video_tab(self))

        # View
        layout_menu = menubar.addMenu('&View(查看)')
        layout_menu.addAction(actions.auto_zoom_dialog(self))

        # Help
        help_menu = menubar.addMenu('&Help(帮助)')
        help_menu.addAction(actions.show_instruction_msg(self))

    def init_toolbar(self):
        self.toolbar = QToolBar('ToolBar', self)
        self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)

        # open and history
        self.toolbar.addAction(actions.open(self))
        self.toolbar.addAction(actions.history(self))
        self.toolbar.addSeparator()
        # refresh and index
        self.toolbar.addAction(actions.refresh(self))
        self.toolbar.addAction(actions.goto_index(self))
        self.toolbar.addSeparator()
        # include and exclude names
        self.toolbar.addAction(actions.include_file_name(self))
        self.toolbar.addAction(actions.exclude_file_name(self))
        self.toolbar.addSeparator()
        # compare and clear compare
        self.toolbar.addAction(actions.compare(self))
        self.toolbar.addAction(actions.clear_compare(self))

        # canvas layout
        self.toolbar.addSeparator()
        self.toolbar.addSeparator()
        self.toolbar.addAction(actions.switch_main_canvas(self))
        self.toolbar.addAction(actions.switch_compare_canvas(self))
        self.toolbar.addAction(actions.switch_preview_canvas(self))

        # others
        self.toolbar.addSeparator()
        self.toolbar.addAction(actions.set_fingerprint(self))

        # help
        self.toolbar.addSeparator()
        self.toolbar.addSeparator()
        self.toolbar.addAction(actions.show_instruction_msg(self))

        # auto zoom
        self.toolbar.addAction(actions.auto_zoom(self))

        self.toolbar.setIconSize(QtCore.QSize(45, 45))
        self.addToolBar(QtCore.Qt.LeftToolBarArea, self.toolbar)

    def init_statusbar(self):
        self.statusBar().showMessage('Welcome to HandyView.')

    def set_statusbar(self, text):
        self.statusBar().showMessage(text)

    def init_central_window(self):
        self.setCentralWidget(self.center_canvas)

    def switch_fullscreen(self):
        if self.full_screen is False:
            self.showFullScreen()
            self.full_screen = True
        else:
            self.showMaximized()
            self.full_screen = False

    def add_dock_window(self):
        # Info
        self.dock_info = QDockWidget('Information Panel', self)
        self.dock_info.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea
                                       | QtCore.Qt.RightDockWidgetArea)
        self.dock_info.setFeatures(QDockWidget.DockWidgetMovable
                                   | QDockWidget.DockWidgetFloatable
                                   | QDockWidget.DockWidgetClosable)
        dockedWidget = QWidget()
        self.dock_info.setWidget(dockedWidget)
        layout = QGridLayout()
        layout.addWidget(self.center_canvas.canvas.zoom_label, 0, 0, 1, 3)
        layout.addWidget(self.center_canvas.canvas.mouse_pos_label, 1, 0, 1, 3)
        color_grid = QGridLayout()
        color_grid.addWidget(self.center_canvas.canvas.mouse_color_title, 0, 0,
                             1, 1)
        color_grid.addWidget(self.center_canvas.canvas.mouse_color_label, 0, 1,
                             1, 3)
        color_grid.addWidget(self.center_canvas.canvas.mouse_rgb_label, 1, 0,
                             1, 3)
        layout.addLayout(color_grid, 2, 0, 1, 3)
        layout.addWidget(HLine(), 3, 0, 1, 3)
        layout.addWidget(self.center_canvas.canvas.selection_pos_label, 4, 0,
                         1, 3)
        layout.addWidget(HLine(), 5, 0, 1, 3)
        layout.addWidget(self.center_canvas.canvas.include_names_label, 6, 0,
                         1, 3)
        layout.addWidget(self.center_canvas.canvas.exclude_names_label, 7, 0,
                         1, 3)
        layout.addWidget(HLine(), 8, 0, 1, 3)
        layout.addWidget(self.center_canvas.canvas.comparison_label, 9, 0, 1,
                         3)
        # update comparison info (for a second open)
        _, img_len_list = self.hvdb.update_path_list()
        show_str = 'Comparison:\n # for each folder:\n\t' + '\n\t'.join(
            map(str, img_len_list))
        if len(img_len_list) > 1:
            self.center_canvas.canvas.comparison_label.setText(show_str)

        # for compact space
        blank_qlabel = QLabel()
        layout.addWidget(blank_qlabel, 10, 0, 20, 3)
        dockedWidget.setLayout(layout)

        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock_info)

    # ---------------------------------------
    # slots: open and history
    # ---------------------------------------
    def open_file_dialog(self):
        # Compare folder should be set in Main Cavans
        if self.canvas_type != 'main':
            self.switch_main_canvas()

        if self.center_canvas.tabs.currentIndex() == 2:  # video
            self.center_canvas.canvas_video.open_files()
        else:
            try:
                with open(os.path.join(ROOT_DIR, 'history.txt'), 'r') as f:
                    history = f.readlines()[0]
                    history = history.strip()
            except Exception:
                history = '.'
            key, ok = QFileDialog.getOpenFileName(self, 'Select an image',
                                                  history)
            if ok:
                self.hvdb.init_path = key
                self.hvdb.get_init_path_list()
                self.center_canvas.canvas.show_image(init=True)
                self.center_canvas.canvas_crop.update_db(self.hvdb)
        self.empty = False

    def open_history(self):
        with open(os.path.join(ROOT_DIR, 'history.txt'), 'r') as f:
            lines = f.readlines()
            lines = [line.strip() for line in lines]
        key, ok = QInputDialog().getItem(self, 'Open File History', 'History:',
                                         lines, 0, True)
        if ok:
            self.hvdb.init_path = key
            self.hvdb.get_init_path_list()
            self.center_canvas.canvas.show_image(init=True)
            self.center_canvas.canvas_crop.update_db(self.hvdb)
        self.empty = False

    # ---------------------------------------
    # slots: refresh and index
    # ---------------------------------------
    def refresh_img_list(self):
        # should be used in Main Canvas
        if self.canvas_type != 'main':
            self.switch_main_canvas()

        self.center_canvas.canvas.update_path_list()
        self.center_canvas.canvas.show_image(init=False)

    def goto_index(self):
        index, ok = QInputDialog.getText(self, 'Go to index', 'Index:',
                                         QLineEdit.Normal, '1')
        if ok:
            if index == '':
                index = 0
            elif index.isdigit():
                index = int(index) - 1
            else:
                return
            self.center_canvas.canvas.goto_index(index)

    # ---------------------------------------
    # slots: include and exclude names
    # ---------------------------------------
    def include_file_name(self):
        # show current include names as the default values
        current_include_names = self.hvdb.include_names
        if current_include_names is None:
            current_include_names = ''
        else:
            current_include_names = ', '.join(current_include_names)

        include_names, ok = QInputDialog.getText(self, 'Include file name',
                                                 'Key word (seprate by ,):',
                                                 QLineEdit.Normal,
                                                 current_include_names)
        if ok:
            if include_names != '':
                self.hvdb.include_names = [
                    v.strip() for v in include_names.split(',')
                ]
                self.hvdb.exclude_names = None
            else:
                self.hvdb.include_names = None
            self.refresh_img_list()

    def exclude_file_name(self):
        # show current exclude names as the default values
        current_exclude_names = self.hvdb.exclude_names
        if current_exclude_names is None:
            current_exclude_names = ''
        else:
            current_exclude_names = ', '.join(current_exclude_names)

        exclude_names, ok = QInputDialog.getText(self, 'Exclude file name',
                                                 'Key word (seprate by ,):',
                                                 QLineEdit.Normal,
                                                 current_exclude_names)
        if ok:
            if exclude_names != '':
                self.hvdb.exclude_names = [
                    v.strip() for v in exclude_names.split(',')
                ]
                self.hvdb.include_names = None
            else:
                self.hvdb.exclude_names = None
            self.refresh_img_list()

    # ---------------------------------------
    # slots: compare and clear compare
    # ---------------------------------------
    def compare_folder(self):
        # Compare folder should be set in Main Cavans
        if self.canvas_type != 'main':
            self.switch_main_canvas()

        key, ok = QFileDialog.getOpenFileName(
            self, 'Select an image', os.path.join(self.hvdb.get_folder(),
                                                  '../'))
        if ok:
            self.center_canvas.canvas.add_cmp_folder(key)

    def clear_compare(self):
        # Compare folder should be set in Main Cavans
        if self.canvas_type != 'main':
            self.switch_main_canvas()

        self.hvdb.folder_list = [self.hvdb.folder_list[0]]
        self.hvdb.path_list = [self.hvdb.path_list[0]]
        self.hvdb.fidx = 0
        # clear the text description in the dock window
        self.center_canvas.canvas.update_path_list()

    # ---------------------------------------
    # slots: canvas layouts
    # ---------------------------------------

    def switch_main_canvas(self):
        if self.canvas_type != 'main':
            self.hvdb.interval = 0
            # TODO: create a new one, which is ugly
            self.center_canvas = CenterWidget(self, self.hvdb)
            self.setCentralWidget(self.center_canvas)
            self.add_dock_window()
            self.canvas_type = 'main'

    def switch_compare_canvas(self):
        if self.canvas_type != 'compare':
            num_compare = self.hvdb.get_folder_len()
            if num_compare == 1:
                num_view, ok = QInputDialog.getText(
                    self, 'Compare Canvas',
                    '# Compare Columns: (options: 2, 3, 4)', QLineEdit.Normal,
                    '2')
                if ok:
                    try:
                        num_view = int(num_view)
                    except Exception:
                        show_msg(icon='Warning',
                                 title='Warning',
                                 text='# Compare Columns should be int.')
                    if num_view > 4 or num_view < 2:
                        show_msg(icon='Warning',
                                 title='Warning',
                                 text='# Compare Columns should be 2, 3, 4.')
                    self.hvdb.interval = num_view - 1
                else:  # when press the 'Cancellation' button
                    self.hvdb.interval = 1
                    num_view = 1
            else:  # for comparing mode
                if not self.hvdb.is_same_len:
                    show_msg('Critical', 'Warning',
                             ('Compare folders have different length, \n'
                              'It may introduce misalignment and errors.'))
                self.hvdb.fidx = 0
                num_view = min(self.hvdb.get_folder_len(), 4)
                show_msg(
                    'Information', 'Compare Canvas',
                    f'Comparsion folder mode.\n # Compare Columns: {num_view}.'
                )

            if num_view > 1:
                self.dock_info.close()
                self.center_canvas.canvas = Canvas(self,
                                                   self.hvdb,
                                                   num_view=num_view)
                self.setCentralWidget(self.center_canvas.canvas)
                self.canvas_type = 'compare'

    def switch_preview_canvas(self):
        show_msg(
            'Information',
            '^_^',
            text=
            ('Has not implemented yet.\nContributions are welcome!\n尚未实现, 欢迎贡献!'
             ))

    # ---------------------------------------
    # slots: canvas tabs
    # ---------------------------------------

    def select_basic_tab(self):
        self.center_canvas.tabs.setCurrentIndex(0)  # 0 for basic

    def select_crop_tab(self):
        self.center_canvas.tabs.setCurrentIndex(1)  # 1 for crop

    def select_video_tab(self):
        self.center_canvas.tabs.setCurrentIndex(2)  # 2 for video

    # ---------------------------------------
    # slots: help
    # ---------------------------------------

    def show_instruction_msg(self):
        from handyview.instruction_text import instruct_text, instruct_text_cn
        msg = MessageDialog(self, instruct_text, instruct_text_cn)
        # msg.setStyleSheet('QLabel{min-width:500 px; font-size: 20px;}')
        msg.setWindowTitle('Instructions')
        msg.exec_()

    def set_fingerprint(self):
        if self.center_canvas.canvas.show_fingerprint:
            self.center_canvas.canvas.show_fingerprint = False
        else:
            self.center_canvas.canvas.show_fingerprint = True
        self.center_canvas.canvas.show_image()

    # ---------------------------------------
    # slots: auto zoom
    # ---------------------------------------
    def auto_zoom(self):
        self.center_canvas.canvas.auto_zoom()

    def auto_zoom_dialog(self):
        target_zoom_width = self.center_canvas.canvas.auto_zoom()
        target_zoom_width, ok = QInputDialog.getText(
            self, 'Auto Zoom', 'Fix image width: (0 for cancelling auto zoom)',
            QLineEdit.Normal, str(target_zoom_width))
        if ok:
            self.center_canvas.canvas.target_zoom_width = int(
                target_zoom_width)
            self.center_canvas.canvas.show_image(init=False)
Ejemplo n.º 3
0
class MusicPlayer(QMainWindow):
    """MusicPlayer houses all of elements that directly interact with the main window."""

    def __init__(self, parent=None):
        """Initialize the QMainWindow widget.

        The window title, window icon, and window size are initialized here as well
        as the following widgets: QMediaPlayer, QMediaPlaylist, QMediaContent, QMenuBar,
        QToolBar, QLabel, QPixmap, QSlider, QDockWidget, QListWidget, QWidget, and
        QVBoxLayout. The connect signals for relavant widgets are also initialized.
        """
        super(MusicPlayer, self).__init__(parent)
        self.setWindowTitle('Mosaic')

        window_icon = utilities.resource_filename('mosaic.images', 'icon.png')
        self.setWindowIcon(QIcon(window_icon))
        self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

        # Initiates Qt objects to be used by MusicPlayer
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.playlist_location = defaults.Settings().playlist_path
        self.content = QMediaContent()
        self.menu = self.menuBar()
        self.toolbar = QToolBar()
        self.art = QLabel()
        self.pixmap = QPixmap()
        self.slider = QSlider(Qt.Horizontal)
        self.duration_label = QLabel()
        self.playlist_dock = QDockWidget('Playlist', self)
        self.library_dock = QDockWidget('Media Library', self)
        self.playlist_view = QListWidget()
        self.library_view = library.MediaLibraryView()
        self.library_model = library.MediaLibraryModel()
        self.preferences = configuration.PreferencesDialog()
        self.widget = QWidget()
        self.layout = QVBoxLayout(self.widget)
        self.duration = 0
        self.playlist_dock_state = None
        self.library_dock_state = None

        # Sets QWidget() as the central widget of the main window
        self.setCentralWidget(self.widget)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.art.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        # Initiates the playlist dock widget and the library dock widget
        self.addDockWidget(defaults.Settings().dock_position, self.playlist_dock)
        self.playlist_dock.setWidget(self.playlist_view)
        self.playlist_dock.setVisible(defaults.Settings().playlist_on_start)
        self.playlist_dock.setFeatures(QDockWidget.DockWidgetClosable)

        self.addDockWidget(defaults.Settings().dock_position, self.library_dock)
        self.library_dock.setWidget(self.library_view)
        self.library_dock.setVisible(defaults.Settings().media_library_on_start)
        self.library_dock.setFeatures(QDockWidget.DockWidgetClosable)
        self.tabifyDockWidget(self.playlist_dock, self.library_dock)

        # Sets the range of the playback slider and sets the playback mode as looping
        self.slider.setRange(0, self.player.duration() / 1000)
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)

        # OSX system menu bar causes conflicts with PyQt5 menu bar
        if sys.platform == 'darwin':
            self.menu.setNativeMenuBar(False)

        # Initiates Settings in the defaults module to give access to settings.toml
        defaults.Settings()

        # Signals that connect to other methods when they're called
        self.player.metaDataChanged.connect(self.display_meta_data)
        self.slider.sliderMoved.connect(self.seek)
        self.player.durationChanged.connect(self.song_duration)
        self.player.positionChanged.connect(self.song_position)
        self.player.stateChanged.connect(self.set_state)
        self.playlist_view.itemActivated.connect(self.activate_playlist_item)
        self.library_view.activated.connect(self.open_media_library)
        self.playlist.currentIndexChanged.connect(self.change_index)
        self.playlist.mediaInserted.connect(self.initialize_playlist)
        self.playlist_dock.visibilityChanged.connect(self.dock_visiblity_change)
        self.library_dock.visibilityChanged.connect(self.dock_visiblity_change)
        self.preferences.dialog_media_library.media_library_line.textChanged.connect(self.change_media_library_path)
        self.preferences.dialog_view_options.dropdown_box.currentIndexChanged.connect(self.change_window_size)
        self.art.mousePressEvent = self.press_playback

        # Creating the menu controls, media controls, and window size of the music player
        self.menu_controls()
        self.media_controls()
        self.load_saved_playlist()

    def menu_controls(self):
        """Initiate the menu bar and add it to the QMainWindow widget."""
        self.file = self.menu.addMenu('File')
        self.edit = self.menu.addMenu('Edit')
        self.playback = self.menu.addMenu('Playback')
        self.view = self.menu.addMenu('View')
        self.help_ = self.menu.addMenu('Help')

        self.file_menu()
        self.edit_menu()
        self.playback_menu()
        self.view_menu()
        self.help_menu()

    def media_controls(self):
        """Create the bottom toolbar and controls used for media playback."""
        self.addToolBar(Qt.BottomToolBarArea, self.toolbar)
        self.toolbar.setMovable(False)

        play_icon = utilities.resource_filename('mosaic.images', 'md_play.png')
        self.play_action = QAction(QIcon(play_icon), 'Play', self)
        self.play_action.triggered.connect(self.player.play)

        stop_icon = utilities.resource_filename('mosaic.images', 'md_stop.png')
        self.stop_action = QAction(QIcon(stop_icon), 'Stop', self)
        self.stop_action.triggered.connect(self.player.stop)

        previous_icon = utilities.resource_filename('mosaic.images', 'md_previous.png')
        self.previous_action = QAction(QIcon(previous_icon), 'Previous', self)
        self.previous_action.triggered.connect(self.previous)

        next_icon = utilities.resource_filename('mosaic.images', 'md_next.png')
        self.next_action = QAction(QIcon(next_icon), 'Next', self)
        self.next_action.triggered.connect(self.playlist.next)

        repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
        self.repeat_action = QAction(QIcon(repeat_icon), 'Repeat', self)
        self.repeat_action.setShortcut('R')
        self.repeat_action.triggered.connect(self.repeat_song)

        self.toolbar.addAction(self.play_action)
        self.toolbar.addAction(self.stop_action)
        self.toolbar.addAction(self.previous_action)
        self.toolbar.addAction(self.next_action)
        self.toolbar.addAction(self.repeat_action)
        self.toolbar.addWidget(self.slider)
        self.toolbar.addWidget(self.duration_label)

    def file_menu(self):
        """Add a file menu to the menu bar.

        The file menu houses the Open File, Open Multiple Files, Open Playlist,
        Open Directory, and Exit Application menu items.
        """
        self.open_action = QAction('Open File', self)
        self.open_action.setShortcut('O')
        self.open_action.triggered.connect(self.open_file)

        self.open_multiple_files_action = QAction('Open Multiple Files', self)
        self.open_multiple_files_action.setShortcut('M')
        self.open_multiple_files_action.triggered.connect(self.open_multiple_files)

        self.open_playlist_action = QAction('Open Playlist', self)
        self.open_playlist_action.setShortcut('CTRL+P')
        self.open_playlist_action.triggered.connect(self.open_playlist)

        self.open_directory_action = QAction('Open Directory', self)
        self.open_directory_action.setShortcut('D')
        self.open_directory_action.triggered.connect(self.open_directory)

        self.save_playlist_action = QAction('Save Playlist', self)
        self.save_playlist_action.setShortcut('CTRL+S')
        self.save_playlist_action.triggered.connect(self.save_playlist)

        self.exit_action = QAction('Quit', self)
        self.exit_action.setShortcut('CTRL+Q')
        self.exit_action.triggered.connect(self.closeEvent)

        self.file.addAction(self.open_action)
        self.file.addAction(self.open_multiple_files_action)
        self.file.addAction(self.open_playlist_action)
        self.file.addAction(self.open_directory_action)
        self.file.addSeparator()
        self.file.addAction(self.save_playlist_action)
        self.file.addSeparator()
        self.file.addAction(self.exit_action)

    def edit_menu(self):
        """Add an edit menu to the menu bar.

        The edit menu houses the preferences item that opens a preferences dialog
        that allows the user to customize features of the music player.
        """
        self.preferences_action = QAction('Preferences', self)
        self.preferences_action.setShortcut('CTRL+SHIFT+P')
        self.preferences_action.triggered.connect(lambda: self.preferences.exec_())

        self.edit.addAction(self.preferences_action)

    def playback_menu(self):
        """Add a playback menu to the menu bar.

        The playback menu houses
        """
        self.play_playback_action = QAction('Play', self)
        self.play_playback_action.setShortcut('P')
        self.play_playback_action.triggered.connect(self.player.play)

        self.stop_playback_action = QAction('Stop', self)
        self.stop_playback_action.setShortcut('S')
        self.stop_playback_action.triggered.connect(self.player.stop)

        self.previous_playback_action = QAction('Previous', self)
        self.previous_playback_action.setShortcut('B')
        self.previous_playback_action.triggered.connect(self.previous)

        self.next_playback_action = QAction('Next', self)
        self.next_playback_action.setShortcut('N')
        self.next_playback_action.triggered.connect(self.playlist.next)

        self.playback.addAction(self.play_playback_action)
        self.playback.addAction(self.stop_playback_action)
        self.playback.addAction(self.previous_playback_action)
        self.playback.addAction(self.next_playback_action)

    def view_menu(self):
        """Add a view menu to the menu bar.

        The view menu houses the Playlist, Media Library, Minimalist View, and Media
        Information menu items. The Playlist item toggles the playlist dock into and
        out of view. The Media Library items toggles the media library dock into and
        out of view. The Minimalist View item resizes the window and shows only the
        menu bar and player controls. The Media Information item opens a dialog that
        shows information relevant to the currently playing song.
        """
        self.dock_action = self.playlist_dock.toggleViewAction()
        self.dock_action.setShortcut('CTRL+ALT+P')

        self.library_dock_action = self.library_dock.toggleViewAction()
        self.library_dock_action.setShortcut('CTRL+ALT+L')

        self.minimalist_view_action = QAction('Minimalist View', self)
        self.minimalist_view_action.setShortcut('CTRL+ALT+M')
        self.minimalist_view_action.setCheckable(True)
        self.minimalist_view_action.triggered.connect(self.minimalist_view)

        self.view_media_info_action = QAction('Media Information', self)
        self.view_media_info_action.setShortcut('CTRL+SHIFT+M')
        self.view_media_info_action.triggered.connect(self.media_information_dialog)

        self.view.addAction(self.dock_action)
        self.view.addAction(self.library_dock_action)
        self.view.addSeparator()
        self.view.addAction(self.minimalist_view_action)
        self.view.addSeparator()
        self.view.addAction(self.view_media_info_action)

    def help_menu(self):
        """Add a help menu to the menu bar.

        The help menu houses the about dialog that shows the user information
        related to the application.
        """
        self.about_action = QAction('About', self)
        self.about_action.setShortcut('H')
        self.about_action.triggered.connect(lambda: about.AboutDialog().exec_())

        self.help_.addAction(self.about_action)

    def open_file(self):
        """Open the selected file and add it to a new playlist."""
        filename, success = QFileDialog.getOpenFileName(self, 'Open File', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly)

        if success:
            file_info = QFileInfo(filename).fileName()
            playlist_item = QListWidgetItem(file_info)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(filename)))
            self.player.setPlaylist(self.playlist)
            playlist_item.setToolTip(file_info)
            self.playlist_view.addItem(playlist_item)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_multiple_files(self):
        """Open the selected files and add them to a new playlist."""
        filenames, success = QFileDialog.getOpenFileNames(self, 'Open Multiple Files', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly)

        if success:
            self.playlist.clear()
            self.playlist_view.clear()
            for file in natsort.natsorted(filenames, alg=natsort.ns.PATH):
                file_info = QFileInfo(file).fileName()
                playlist_item = QListWidgetItem(file_info)
                self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                self.player.setPlaylist(self.playlist)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)
                self.playlist_view.setCurrentRow(0)
                self.player.play()

    def open_playlist(self):
        """Load an M3U or PLS file into a new playlist."""
        playlist, success = QFileDialog.getOpenFileName(self, 'Open Playlist', '', 'Playlist (*.m3u *.pls)', '', QFileDialog.ReadOnly)

        if success:
            playlist = QUrl.fromLocalFile(playlist)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def save_playlist(self):
        """Save the media in the playlist dock as a new M3U playlist."""
        playlist, success = QFileDialog.getSaveFileName(self, 'Save Playlist', '', 'Playlist (*.m3u)', '')
        if success:
            saved_playlist = "{}.m3u" .format(playlist)
            self.playlist.save(QUrl().fromLocalFile(saved_playlist), "m3u")

    def load_saved_playlist(self):
        """Load the saved playlist if user setting permits."""
        saved_playlist = "{}/.m3u" .format(self.playlist_location)
        if os.path.exists(saved_playlist):
            playlist = QUrl().fromLocalFile(saved_playlist)
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)

    def open_directory(self):
        """Open the selected directory and add the files within to an empty playlist."""
        directory = QFileDialog.getExistingDirectory(self, 'Open Directory', '', QFileDialog.ReadOnly)

        if directory:
            self.playlist.clear()
            self.playlist_view.clear()
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

            self.player.setPlaylist(self.playlist)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_media_library(self, index):
        """Open a directory or file from the media library into an empty playlist."""
        self.playlist.clear()
        self.playlist_view.clear()

        if self.library_model.fileName(index).endswith(('mp3', 'flac')):
            self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(self.library_model.filePath(index))))
            self.playlist_view.addItem(self.library_model.fileName(index))

        elif self.library_model.isDir(index):
            directory = self.library_model.filePath(index)
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

        self.player.setPlaylist(self.playlist)
        self.player.play()

    def display_meta_data(self):
        """Display the current song's metadata in the main window.

        If the current song contains metadata, its cover art is extracted and shown in
        the main window while the track number, artist, album, and track title are shown
        in the window title.
        """
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
            (album, artist, title, track_number, *__, artwork) = metadata.metadata(file_path)

            try:
                self.pixmap.loadFromData(artwork)
            except TypeError:
                self.pixmap = QPixmap(artwork)

            meta_data = '{} - {} - {} - {}' .format(track_number, artist, album, title)

            self.setWindowTitle(meta_data)
            self.art.setScaledContents(True)
            self.art.setPixmap(self.pixmap)
            self.layout.addWidget(self.art)

    def initialize_playlist(self, start):
        """Display playlist and reset playback mode when media inserted into playlist."""
        if start == 0:
            if self.library_dock.isVisible():
                self.playlist_dock.setVisible(True)
                self.playlist_dock.show()
                self.playlist_dock.raise_()

            if self.playlist.playbackMode() != QMediaPlaylist.Sequential:
                self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
                repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
                self.repeat_action.setIcon(QIcon(repeat_icon))

    def press_playback(self, event):
        """Change the playback of the player on cover art mouse event.

        When the cover art is clicked, the player will play the media if the player is
        either paused or stopped. If the media is playing, the media is set
        to pause.
        """
        if event.button() == 1 and configuration.Playback().cover_art_playback.isChecked():
            if (self.player.state() == QMediaPlayer.StoppedState or
                    self.player.state() == QMediaPlayer.PausedState):
                self.player.play()
            elif self.player.state() == QMediaPlayer.PlayingState:
                self.player.pause()

    def seek(self, seconds):
        """Set the position of the song to the position dragged to by the user."""
        self.player.setPosition(seconds * 1000)

    def song_duration(self, duration):
        """Set the slider to the duration of the currently played media."""
        duration /= 1000
        self.duration = duration
        self.slider.setMaximum(duration)

    def song_position(self, progress):
        """Move the horizontal slider in sync with the duration of the song.

        The progress is relayed to update_duration() in order
        to display the time label next to the slider.
        """
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.update_duration(progress)

    def update_duration(self, current_duration):
        """Calculate the time played and the length of the song.

        Both of these times are sent to duration_label() in order to display the
        times on the toolbar.
        """
        duration = self.duration

        if current_duration or duration:
            time_played = QTime((current_duration / 3600) % 60, (current_duration / 60) % 60,
                                (current_duration % 60), (current_duration * 1000) % 1000)
            song_length = QTime((duration / 3600) % 60, (duration / 60) % 60, (duration % 60),
                                (duration * 1000) % 1000)

            if duration > 3600:
                time_format = "hh:mm:ss"
            else:
                time_format = "mm:ss"

            time_display = "{} / {}" .format(time_played.toString(time_format), song_length.toString(time_format))

        else:
            time_display = ""

        self.duration_label.setText(time_display)

    def set_state(self, state):
        """Change the icon in the toolbar in relation to the state of the player.

        The play icon changes to the pause icon when a song is playing and
        the pause icon changes back to the play icon when either paused or
        stopped.
        """
        if self.player.state() == QMediaPlayer.PlayingState:
            pause_icon = utilities.resource_filename('mosaic.images', 'md_pause.png')
            self.play_action.setIcon(QIcon(pause_icon))
            self.play_action.triggered.connect(self.player.pause)

        elif (self.player.state() == QMediaPlayer.PausedState or self.player.state() == QMediaPlayer.StoppedState):
            self.play_action.triggered.connect(self.player.play)
            play_icon = utilities.resource_filename('mosaic.images', 'md_play.png')
            self.play_action.setIcon(QIcon(play_icon))

    def previous(self):
        """Move to the previous song in the playlist.

        Moves to the previous song in the playlist if the current song is less
        than five seconds in. Otherwise, restarts the current song.
        """
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def repeat_song(self):
        """Set the current media to repeat and change the repeat icon accordingly.

        There are four playback modes: repeat none, repeat all, repeat once, and shuffle.
        Clicking the repeat button cycles through each playback mode.
        """
        if self.playlist.playbackMode() == QMediaPlaylist.Sequential:
            self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
            repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_all.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Loop:
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_once.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.CurrentItemInLoop:
            self.playlist.setPlaybackMode(QMediaPlaylist.Random)
            repeat_icon = utilities.resource_filename('mosaic.images', 'md_shuffle.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Random:
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
            repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

    def activate_playlist_item(self, item):
        """Set the active media to the playlist item dobule-clicked on by the user."""
        current_index = self.playlist_view.row(item)
        if self.playlist.currentIndex() != current_index:
            self.playlist.setCurrentIndex(current_index)

        if self.player.state() != QMediaPlayer.PlayingState:
            self.player.play()

    def change_index(self, row):
        """Highlight the row in the playlist of the active media."""
        self.playlist_view.setCurrentRow(row)

    def minimalist_view(self):
        """Resize the window to only show the menu bar and audio controls."""
        if self.minimalist_view_action.isChecked():

            if self.playlist_dock.isVisible():
                self.playlist_dock_state = True
            if self.library_dock.isVisible():
                self.library_dock_state = True

            self.library_dock.close()
            self.playlist_dock.close()

            QTimer.singleShot(10, lambda: self.resize(500, 0))

        else:
            self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

            if self.library_dock_state:
                self.library_dock.setVisible(True)

            if self.playlist_dock_state:
                self.playlist_dock.setVisible(True)

    def dock_visiblity_change(self, visible):
        """Change the size of the main window when the docks are toggled."""
        if visible and self.playlist_dock.isVisible() and not self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.playlist_dock.width() + 6,
                        self.height())

        elif visible and not self.playlist_dock.isVisible() and self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.library_dock.width() + 6,
                        self.height())

        elif visible and self.playlist_dock.isVisible() and self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.library_dock.width() + 6,
                        self.height())

        elif (not visible and not self.playlist_dock.isVisible() and not
                self.library_dock.isVisible()):
            self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

    def media_information_dialog(self):
        """Show a dialog of the current song's metadata."""
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
        else:
            file_path = None
        dialog = information.InformationDialog(file_path)
        dialog.exec_()

    def change_window_size(self):
        """Change the window size of the music player."""
        self.playlist_dock.close()
        self.library_dock.close()
        self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

    def change_media_library_path(self, path):
        """Change the media library path to the new path selected in the preferences dialog."""
        self.library_model.setRootPath(path)
        self.library_view.setModel(self.library_model)
        self.library_view.setRootIndex(self.library_model.index(path))

    def closeEvent(self, event):
        """Override the PyQt close event in order to handle save playlist on close."""
        playlist = "{}/.m3u" .format(self.playlist_location)
        if defaults.Settings().save_playlist_on_close:
            self.playlist.save(QUrl().fromLocalFile(playlist), "m3u")
        else:
            if os.path.exists(playlist):
                os.remove(playlist)
        QApplication.quit()
Ejemplo n.º 4
0
class MyApp(QMainWindow):
    def __init__(self):
        super(MyApp, self).__init__()
        QApplication.processEvents()
        self.childArea = childWindow()
        self.tool_bar = self.addToolBar('工具栏')
        self.action_right_rotate = QAction(QIcon("icons/右旋转.png"), "向右旋转90",
                                           self)
        self.action_left_rotate = QAction(QIcon("icons/左旋转.png"), "向左旋转90°",
                                          self)
        self.action_histogram = QAction(QIcon("icons/直方图.png"), "直方图", self)
        self.action_right_rotate.triggered.connect(self.right_rotate)
        self.action_left_rotate.triggered.connect(self.left_rotate)
        self.action_histogram.triggered.connect(self.histogram)
        # 将上述动作关联到某一个菜单项里面
        self.tool_bar.addActions(
            (self.action_left_rotate, self.action_right_rotate,
             self.action_histogram))

        self.useListWidget = UsedListWidget(self)
        self.funcListWidget = FuncListWidget(self)
        self.stackedWidget = StackedWidget(self)
        self.fileSystemTreeView = FileSystemTreeView(self)
        self.graphicsView = GraphicsView(self)

        self.dock_file = QDockWidget(self)
        self.dock_file.setWidget(self.fileSystemTreeView)
        self.dock_file.setTitleBarWidget(QLabel('目录'))
        self.dock_file.setFeatures(QDockWidget.NoDockWidgetFeatures)

        self.dock_func = QDockWidget(self)
        self.dock_func.setWidget(self.funcListWidget)
        self.dock_func.setTitleBarWidget(QLabel('图像操作'))
        self.dock_func.setFeatures(QDockWidget.NoDockWidgetFeatures)

        self.dock_used = QDockWidget(self)
        self.dock_used.setWidget(self.useListWidget)
        self.dock_used.setTitleBarWidget(QLabel('已选操作'))
        self.dock_used.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.dock_used.setFeatures(QDockWidget.NoDockWidgetFeatures)

        self.dock_attr = QDockWidget(self)
        self.dock_attr.setWidget(self.stackedWidget)
        self.dock_attr.setTitleBarWidget(QLabel('属性'))
        self.dock_attr.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.dock_attr.close()

        self.setCentralWidget(self.graphicsView)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_file)
        self.dock_file.setMinimumWidth(400)
        self.dock_file.showMinimized()
        self.addDockWidget(Qt.TopDockWidgetArea, self.dock_func)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_used)
        self.dock_used.setMinimumWidth(400)
        self.dock_used.showMinimized()
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_attr)
        self.dock_attr.setMinimumHeight(500)

        self.setWindowTitle('数字图像处理')
        self.setWindowIcon(QIcon('icons/main.png'))
        self.src_img = None
        self.cur_img = None

    def update_image(self):
        if self.src_img is None:
            return
        img = self.process_image()
        self.cur_img = img
        self.graphicsView.update_image(img)

    def change_image(self, img):
        self.src_img = img
        img = self.process_image()
        self.cur_img = img
        self.graphicsView.change_image(img)

    def process_image(self):
        img = self.src_img.copy()
        for i in range(self.useListWidget.count()):
            img = self.useListWidget.item(i)(img)
        return img

    def right_rotate(self):
        self.cur_img = ratate(self.cur_img, 90)
        self.graphicsView.rotate(90)

    def left_rotate(self):
        self.cur_img = ratate(self.cur_img, -90)
        self.graphicsView.rotate(-90)

    def histogram(self):
        color = ('b', 'g', 'r')
        img = self.cur_img
        shape = img.shape
        if len(shape) != 3:
            img = cvtColor(self.cur_img, COLOR_GRAY2BGR)
        for i, col in enumerate(color):
            histr = calcHist([img], [i], None, [256], [0, 256])
            histr = histr.flatten()
            plt.plot(range(256), histr, color=col)
            plt.xlim([0, 256])
        plt.savefig('histogram.png')
        plt.close()
        self.img = imread('./histogram.png')
        self.childArea.display(self.img)
        self.childArea.show()
Ejemplo n.º 5
0
class MusicPlayer(QMainWindow):
    """MusicPlayer houses all of elements that directly interact with the main window."""
    def __init__(self, parent=None):
        """Initialize the QMainWindow widget.

        The window title, window icon, and window size are initialized here as well
        as the following widgets: QMediaPlayer, QMediaPlaylist, QMediaContent, QMenuBar,
        QToolBar, QLabel, QPixmap, QSlider, QDockWidget, QListWidget, QWidget, and
        QVBoxLayout. The connect signals for relavant widgets are also initialized.
        """
        super(MusicPlayer, self).__init__(parent)
        self.setWindowTitle('Mosaic')

        window_icon = utilities.resource_filename('mosaic.images', 'icon.png')
        self.setWindowIcon(QIcon(window_icon))
        self.resize(defaults.Settings().window_size,
                    defaults.Settings().window_size + 63)

        # Initiates Qt objects to be used by MusicPlayer
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.playlist_location = defaults.Settings().playlist_path
        self.content = QMediaContent()
        self.menu = self.menuBar()
        self.toolbar = QToolBar()
        self.art = QLabel()
        self.pixmap = QPixmap()
        self.slider = QSlider(Qt.Horizontal)
        self.duration_label = QLabel()
        self.playlist_dock = QDockWidget('Playlist', self)
        self.library_dock = QDockWidget('Media Library', self)
        self.playlist_view = QListWidget()
        self.library_view = library.MediaLibraryView()
        self.library_model = library.MediaLibraryModel()
        self.preferences = configuration.PreferencesDialog()
        self.widget = QWidget()
        self.layout = QVBoxLayout(self.widget)
        self.duration = 0
        self.playlist_dock_state = None
        self.library_dock_state = None

        # Sets QWidget() as the central widget of the main window
        self.setCentralWidget(self.widget)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.art.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        # Initiates the playlist dock widget and the library dock widget
        self.addDockWidget(defaults.Settings().dock_position,
                           self.playlist_dock)
        self.playlist_dock.setWidget(self.playlist_view)
        self.playlist_dock.setVisible(defaults.Settings().playlist_on_start)
        self.playlist_dock.setFeatures(QDockWidget.DockWidgetClosable)

        self.addDockWidget(defaults.Settings().dock_position,
                           self.library_dock)
        self.library_dock.setWidget(self.library_view)
        self.library_dock.setVisible(
            defaults.Settings().media_library_on_start)
        self.library_dock.setFeatures(QDockWidget.DockWidgetClosable)
        self.tabifyDockWidget(self.playlist_dock, self.library_dock)

        # Sets the range of the playback slider and sets the playback mode as looping
        self.slider.setRange(0, self.player.duration() / 1000)
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)

        # OSX system menu bar causes conflicts with PyQt5 menu bar
        if sys.platform == 'darwin':
            self.menu.setNativeMenuBar(False)

        # Initiates Settings in the defaults module to give access to settings.toml
        defaults.Settings()

        # Signals that connect to other methods when they're called
        self.player.metaDataChanged.connect(self.display_meta_data)
        self.slider.sliderMoved.connect(self.seek)
        self.player.durationChanged.connect(self.song_duration)
        self.player.positionChanged.connect(self.song_position)
        self.player.stateChanged.connect(self.set_state)
        self.playlist_view.itemActivated.connect(self.activate_playlist_item)
        self.library_view.activated.connect(self.open_media_library)
        self.playlist.currentIndexChanged.connect(self.change_index)
        self.playlist.mediaInserted.connect(self.initialize_playlist)
        self.playlist_dock.visibilityChanged.connect(
            self.dock_visiblity_change)
        self.library_dock.visibilityChanged.connect(self.dock_visiblity_change)
        self.preferences.dialog_media_library.media_library_line.textChanged.connect(
            self.change_media_library_path)
        self.preferences.dialog_view_options.dropdown_box.currentIndexChanged.connect(
            self.change_window_size)
        self.art.mousePressEvent = self.press_playback

        # Creating the menu controls, media controls, and window size of the music player
        self.menu_controls()
        self.media_controls()
        self.load_saved_playlist()

    def menu_controls(self):
        """Initiate the menu bar and add it to the QMainWindow widget."""
        self.file = self.menu.addMenu('File')
        self.edit = self.menu.addMenu('Edit')
        self.playback = self.menu.addMenu('Playback')
        self.view = self.menu.addMenu('View')
        self.help_ = self.menu.addMenu('Help')

        self.file_menu()
        self.edit_menu()
        self.playback_menu()
        self.view_menu()
        self.help_menu()

    def media_controls(self):
        """Create the bottom toolbar and controls used for media playback."""
        self.addToolBar(Qt.BottomToolBarArea, self.toolbar)
        self.toolbar.setMovable(False)

        play_icon = utilities.resource_filename('mosaic.images', 'md_play.png')
        self.play_action = QAction(QIcon(play_icon), 'Play', self)
        self.play_action.triggered.connect(self.player.play)

        stop_icon = utilities.resource_filename('mosaic.images', 'md_stop.png')
        self.stop_action = QAction(QIcon(stop_icon), 'Stop', self)
        self.stop_action.triggered.connect(self.player.stop)

        previous_icon = utilities.resource_filename('mosaic.images',
                                                    'md_previous.png')
        self.previous_action = QAction(QIcon(previous_icon), 'Previous', self)
        self.previous_action.triggered.connect(self.previous)

        next_icon = utilities.resource_filename('mosaic.images', 'md_next.png')
        self.next_action = QAction(QIcon(next_icon), 'Next', self)
        self.next_action.triggered.connect(self.playlist.next)

        repeat_icon = utilities.resource_filename('mosaic.images',
                                                  'md_repeat_none.png')
        self.repeat_action = QAction(QIcon(repeat_icon), 'Repeat', self)
        self.repeat_action.triggered.connect(self.repeat_song)

        self.toolbar.addAction(self.play_action)
        self.toolbar.addAction(self.stop_action)
        self.toolbar.addAction(self.previous_action)
        self.toolbar.addAction(self.next_action)
        self.toolbar.addAction(self.repeat_action)
        self.toolbar.addWidget(self.slider)
        self.toolbar.addWidget(self.duration_label)

    def file_menu(self):
        """Add a file menu to the menu bar.

        The file menu houses the Open File, Open Multiple Files, Open Playlist,
        Open Directory, and Exit Application menu items.
        """
        self.open_action = QAction('Open File', self)
        self.open_action.setShortcut('O')
        self.open_action.triggered.connect(self.open_file)

        self.open_multiple_files_action = QAction('Open Multiple Files', self)
        self.open_multiple_files_action.setShortcut('M')
        self.open_multiple_files_action.triggered.connect(
            self.open_multiple_files)

        self.open_playlist_action = QAction('Open Playlist', self)
        self.open_playlist_action.setShortcut('CTRL+P')
        self.open_playlist_action.triggered.connect(self.open_playlist)

        self.open_directory_action = QAction('Open Directory', self)
        self.open_directory_action.setShortcut('D')
        self.open_directory_action.triggered.connect(self.open_directory)

        self.save_playlist_action = QAction('Save Playlist', self)
        self.save_playlist_action.setShortcut('CTRL+S')
        self.save_playlist_action.triggered.connect(self.save_playlist)

        self.exit_action = QAction('Quit', self)
        self.exit_action.setShortcut('CTRL+Q')
        self.exit_action.triggered.connect(self.closeEvent)

        self.file.addAction(self.open_action)
        self.file.addAction(self.open_multiple_files_action)
        self.file.addAction(self.open_playlist_action)
        self.file.addAction(self.open_directory_action)
        self.file.addSeparator()
        self.file.addAction(self.save_playlist_action)
        self.file.addSeparator()
        self.file.addAction(self.exit_action)

    def edit_menu(self):
        """Add an edit menu to the menu bar.

        The edit menu houses the preferences item that opens a preferences dialog
        that allows the user to customize features of the music player.
        """
        self.preferences_action = QAction('Preferences', self)
        self.preferences_action.setShortcut('CTRL+SHIFT+P')
        self.preferences_action.triggered.connect(
            lambda: self.preferences.exec_())

        self.edit.addAction(self.preferences_action)

    def playback_menu(self):
        """Add a playback menu to the menu bar.

        The playback menu houses
        """
        self.play_playback_action = QAction('Play', self)
        self.play_playback_action.setShortcut('P')
        self.play_playback_action.triggered.connect(self.player.play)

        self.stop_playback_action = QAction('Stop', self)
        self.stop_playback_action.setShortcut('S')
        self.stop_playback_action.triggered.connect(self.player.stop)

        self.previous_playback_action = QAction('Previous', self)
        self.previous_playback_action.setShortcut('B')
        self.previous_playback_action.triggered.connect(self.previous)

        self.next_playback_action = QAction('Next', self)
        self.next_playback_action.setShortcut('N')
        self.next_playback_action.triggered.connect(self.playlist.next)

        self.playback.addAction(self.play_playback_action)
        self.playback.addAction(self.stop_playback_action)
        self.playback.addAction(self.previous_playback_action)
        self.playback.addAction(self.next_playback_action)

    def view_menu(self):
        """Add a view menu to the menu bar.

        The view menu houses the Playlist, Media Library, Minimalist View, and Media
        Information menu items. The Playlist item toggles the playlist dock into and
        out of view. The Media Library items toggles the media library dock into and
        out of view. The Minimalist View item resizes the window and shows only the
        menu bar and player controls. The Media Information item opens a dialog that
        shows information relevant to the currently playing song.
        """
        self.dock_action = self.playlist_dock.toggleViewAction()
        self.dock_action.setShortcut('CTRL+ALT+P')

        self.library_dock_action = self.library_dock.toggleViewAction()
        self.library_dock_action.setShortcut('CTRL+ALT+L')

        self.minimalist_view_action = QAction('Minimalist View', self)
        self.minimalist_view_action.setShortcut('CTRL+ALT+M')
        self.minimalist_view_action.setCheckable(True)
        self.minimalist_view_action.triggered.connect(self.minimalist_view)

        self.view_media_info_action = QAction('Media Information', self)
        self.view_media_info_action.setShortcut('CTRL+SHIFT+M')
        self.view_media_info_action.triggered.connect(
            self.media_information_dialog)

        self.view.addAction(self.dock_action)
        self.view.addAction(self.library_dock_action)
        self.view.addSeparator()
        self.view.addAction(self.minimalist_view_action)
        self.view.addSeparator()
        self.view.addAction(self.view_media_info_action)

    def help_menu(self):
        """Add a help menu to the menu bar.

        The help menu houses the about dialog that shows the user information
        related to the application.
        """
        self.about_action = QAction('About', self)
        self.about_action.setShortcut('H')
        self.about_action.triggered.connect(
            lambda: about.AboutDialog().exec_())

        self.help_.addAction(self.about_action)

    def open_file(self):
        """Open the selected file and add it to a new playlist."""
        filename, success = QFileDialog.getOpenFileName(
            self, 'Open File', '', 'Audio (*.mp3 *.flac)', '',
            QFileDialog.ReadOnly)

        if success:
            file_info = QFileInfo(filename).fileName()
            playlist_item = QListWidgetItem(file_info)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.addMedia(
                QMediaContent(QUrl().fromLocalFile(filename)))
            self.player.setPlaylist(self.playlist)
            playlist_item.setToolTip(file_info)
            self.playlist_view.addItem(playlist_item)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_multiple_files(self):
        """Open the selected files and add them to a new playlist."""
        filenames, success = QFileDialog.getOpenFileNames(
            self, 'Open Multiple Files', '', 'Audio (*.mp3 *.flac)', '',
            QFileDialog.ReadOnly)

        if success:
            self.playlist.clear()
            self.playlist_view.clear()
            for file in natsort.natsorted(filenames, alg=natsort.ns.PATH):
                file_info = QFileInfo(file).fileName()
                playlist_item = QListWidgetItem(file_info)
                self.playlist.addMedia(
                    QMediaContent(QUrl().fromLocalFile(file)))
                self.player.setPlaylist(self.playlist)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)
                self.playlist_view.setCurrentRow(0)
                self.player.play()

    def open_playlist(self):
        """Load an M3U or PLS file into a new playlist."""
        playlist, success = QFileDialog.getOpenFileName(
            self, 'Open Playlist', '', 'Playlist (*.m3u *.pls)', '',
            QFileDialog.ReadOnly)

        if success:
            playlist = QUrl.fromLocalFile(playlist)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(
                    song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def save_playlist(self):
        """Save the media in the playlist dock as a new M3U playlist."""
        playlist, success = QFileDialog.getSaveFileName(
            self, 'Save Playlist', '', 'Playlist (*.m3u)', '')
        if success:
            saved_playlist = "{}.m3u".format(playlist)
            self.playlist.save(QUrl().fromLocalFile(saved_playlist), "m3u")

    def load_saved_playlist(self):
        """Load the saved playlist if user setting permits."""
        saved_playlist = "{}/.m3u".format(self.playlist_location)
        if os.path.exists(saved_playlist):
            playlist = QUrl().fromLocalFile(saved_playlist)
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(
                    song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)

    def open_directory(self):
        """Open the selected directory and add the files within to an empty playlist."""
        directory = QFileDialog.getExistingDirectory(self, 'Open Directory',
                                                     '', QFileDialog.ReadOnly)

        if directory:
            self.playlist.clear()
            self.playlist_view.clear()
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(
                            QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

            self.player.setPlaylist(self.playlist)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_media_library(self, index):
        """Open a directory or file from the media library into an empty playlist."""
        self.playlist.clear()
        self.playlist_view.clear()

        if self.library_model.fileName(index).endswith(('mp3', 'flac')):
            self.playlist.addMedia(
                QMediaContent(QUrl().fromLocalFile(
                    self.library_model.filePath(index))))
            self.playlist_view.addItem(self.library_model.fileName(index))

        elif self.library_model.isDir(index):
            directory = self.library_model.filePath(index)
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(
                            QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

        self.player.setPlaylist(self.playlist)
        self.player.play()

    def display_meta_data(self):
        """Display the current song's metadata in the main window.

        If the current song contains metadata, its cover art is extracted and shown in
        the main window while the track number, artist, album, and track title are shown
        in the window title.
        """
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
            (album, artist, title, track_number, *__,
             artwork) = metadata.metadata(file_path)

            try:
                self.pixmap.loadFromData(artwork)
            except TypeError:
                self.pixmap = QPixmap(artwork)

            meta_data = '{} - {} - {} - {}'.format(track_number, artist, album,
                                                   title)

            self.setWindowTitle(meta_data)
            self.art.setScaledContents(True)
            self.art.setPixmap(self.pixmap)
            self.layout.addWidget(self.art)

    def initialize_playlist(self, start):
        """Display playlist and reset playback mode when media inserted into playlist."""
        if start == 0:
            if self.library_dock.isVisible():
                self.playlist_dock.setVisible(True)
                self.playlist_dock.show()
                self.playlist_dock.raise_()

            if self.playlist.playbackMode() != QMediaPlaylist.Sequential:
                self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
                repeat_icon = utilities.resource_filename(
                    'mosaic.images', 'md_repeat_none.png')
                self.repeat_action.setIcon(QIcon(repeat_icon))

    def press_playback(self, event):
        """Change the playback of the player on cover art mouse event.

        When the cover art is clicked, the player will play the media if the player is
        either paused or stopped. If the media is playing, the media is set
        to pause.
        """
        if event.button() == 1 and configuration.Playback(
        ).cover_art_playback.isChecked():
            if (self.player.state() == QMediaPlayer.StoppedState
                    or self.player.state() == QMediaPlayer.PausedState):
                self.player.play()
            elif self.player.state() == QMediaPlayer.PlayingState:
                self.player.pause()

    def seek(self, seconds):
        """Set the position of the song to the position dragged to by the user."""
        self.player.setPosition(seconds * 1000)

    def song_duration(self, duration):
        """Set the slider to the duration of the currently played media."""
        duration /= 1000
        self.duration = duration
        self.slider.setMaximum(duration)

    def song_position(self, progress):
        """Move the horizontal slider in sync with the duration of the song.

        The progress is relayed to update_duration() in order
        to display the time label next to the slider.
        """
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.update_duration(progress)

    def update_duration(self, current_duration):
        """Calculate the time played and the length of the song.

        Both of these times are sent to duration_label() in order to display the
        times on the toolbar.
        """
        duration = self.duration

        if current_duration or duration:
            time_played = QTime(
                (current_duration / 3600) % 60, (current_duration / 60) % 60,
                (current_duration % 60), (current_duration * 1000) % 1000)
            song_length = QTime((duration / 3600) % 60, (duration / 60) % 60,
                                (duration % 60), (duration * 1000) % 1000)

            if duration > 3600:
                time_format = "hh:mm:ss"
            else:
                time_format = "mm:ss"

            time_display = "{} / {}".format(time_played.toString(time_format),
                                            song_length.toString(time_format))

        else:
            time_display = ""

        self.duration_label.setText(time_display)

    def set_state(self, state):
        """Change the icon in the toolbar in relation to the state of the player.

        The play icon changes to the pause icon when a song is playing and
        the pause icon changes back to the play icon when either paused or
        stopped.
        """
        if self.player.state() == QMediaPlayer.PlayingState:
            pause_icon = utilities.resource_filename('mosaic.images',
                                                     'md_pause.png')
            self.play_action.setIcon(QIcon(pause_icon))
            self.play_action.triggered.connect(self.player.pause)

        elif (self.player.state() == QMediaPlayer.PausedState
              or self.player.state() == QMediaPlayer.StoppedState):
            self.play_action.triggered.connect(self.player.play)
            play_icon = utilities.resource_filename('mosaic.images',
                                                    'md_play.png')
            self.play_action.setIcon(QIcon(play_icon))

    def previous(self):
        """Move to the previous song in the playlist.

        Moves to the previous song in the playlist if the current song is less
        than five seconds in. Otherwise, restarts the current song.
        """
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def repeat_song(self):
        """Set the current media to repeat and change the repeat icon accordingly.

        There are four playback modes: repeat none, repeat all, repeat once, and shuffle.
        Clicking the repeat button cycles through each playback mode.
        """
        if self.playlist.playbackMode() == QMediaPlaylist.Sequential:
            self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
            repeat_on_icon = utilities.resource_filename(
                'mosaic.images', 'md_repeat_all.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Loop:
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            repeat_on_icon = utilities.resource_filename(
                'mosaic.images', 'md_repeat_once.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.CurrentItemInLoop:
            self.playlist.setPlaybackMode(QMediaPlaylist.Random)
            repeat_icon = utilities.resource_filename('mosaic.images',
                                                      'md_shuffle.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Random:
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
            repeat_icon = utilities.resource_filename('mosaic.images',
                                                      'md_repeat_none.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

    def activate_playlist_item(self, item):
        """Set the active media to the playlist item dobule-clicked on by the user."""
        current_index = self.playlist_view.row(item)
        if self.playlist.currentIndex() != current_index:
            self.playlist.setCurrentIndex(current_index)

        if self.player.state() != QMediaPlayer.PlayingState:
            self.player.play()

    def change_index(self, row):
        """Highlight the row in the playlist of the active media."""
        self.playlist_view.setCurrentRow(row)

    def minimalist_view(self):
        """Resize the window to only show the menu bar and audio controls."""
        if self.minimalist_view_action.isChecked():

            if self.playlist_dock.isVisible():
                self.playlist_dock_state = True
            if self.library_dock.isVisible():
                self.library_dock_state = True

            self.library_dock.close()
            self.playlist_dock.close()

            QTimer.singleShot(10, lambda: self.resize(500, 0))

        else:
            self.resize(defaults.Settings().window_size,
                        defaults.Settings().window_size + 63)

            if self.library_dock_state:
                self.library_dock.setVisible(True)

            if self.playlist_dock_state:
                self.playlist_dock.setVisible(True)

    def dock_visiblity_change(self, visible):
        """Change the size of the main window when the docks are toggled."""
        if visible and self.playlist_dock.isVisible(
        ) and not self.library_dock.isVisible():
            self.resize(
                defaults.Settings().window_size + self.playlist_dock.width() +
                6, self.height())

        elif visible and not self.playlist_dock.isVisible(
        ) and self.library_dock.isVisible():
            self.resize(
                defaults.Settings().window_size + self.library_dock.width() +
                6, self.height())

        elif visible and self.playlist_dock.isVisible(
        ) and self.library_dock.isVisible():
            self.resize(
                defaults.Settings().window_size + self.library_dock.width() +
                6, self.height())

        elif (not visible and not self.playlist_dock.isVisible()
              and not self.library_dock.isVisible()):
            self.resize(defaults.Settings().window_size,
                        defaults.Settings().window_size + 63)

    def media_information_dialog(self):
        """Show a dialog of the current song's metadata."""
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
        else:
            file_path = None
        dialog = information.InformationDialog(file_path)
        dialog.exec_()

    def change_window_size(self):
        """Change the window size of the music player."""
        self.playlist_dock.close()
        self.library_dock.close()
        self.resize(defaults.Settings().window_size,
                    defaults.Settings().window_size + 63)

    def change_media_library_path(self, path):
        """Change the media library path to the new path selected in the preferences dialog."""
        self.library_model.setRootPath(path)
        self.library_view.setModel(self.library_model)
        self.library_view.setRootIndex(self.library_model.index(path))

    def closeEvent(self, event):
        """Override the PyQt close event in order to handle save playlist on close."""
        playlist = "{}/.m3u".format(self.playlist_location)
        if defaults.Settings().save_playlist_on_close:
            self.playlist.save(QUrl().fromLocalFile(playlist), "m3u")
        else:
            if os.path.exists(playlist):
                os.remove(playlist)
        QApplication.quit()
Ejemplo n.º 6
0
class Jigsaw(QMainWindow, Ui_MainWindow):
    """
    拼图主程序
    """
    saveData = []

    def __init__(self, parent=None):
        """
        界面初始化
        载入历史时间
        记录时间初始化
        载入游戏
        """
        super(Jigsaw, self).__init__(parent)
        self.setupUi(self)
        self.initUi()
        self.puzzleImage = QPixmap("./img/Peppa.png")
        self.saveData = self.loadTime()
        self.dock2 = QDockWidget("完整的图片", self)
        self.dock2.resize(400, 400)
        self.setupPuzzle()
        self.initTimeUi()

    def initUi(self):
        """
        一些简单布局
        """
        self.setWindowFlags(Qt.Dialog)
        self.setWhatsThis("这是一个拼图小游戏")
        frameLayout = QHBoxLayout(self.frame)
        self.puzzleshow = PuzzleShow(400)
        self.puzzlepiece = PuzzlePiece(self.puzzleshow.pieceSize())
        frameLayout.addWidget(self.puzzlepiece)
        frameLayout.addWidget(self.puzzleshow)
        self.setCentralWidget(self.frame)

        self.puzzleshow.puzzleCompleted.connect(self.setCompleted)
        # 当我们完成游戏的时候会发出puzzleCompleted信号,这个信号是连接setCompleted()函数的

    def initTimeUi(self):
        """
        游戏时间初始化
        """
        self.dock = QDockWidget("游戏时间", self)
        self.label = QLabel("当前游戏用时:0秒,最佳时间:0秒")
        self.label.setStyleSheet("color: rgb(255, 0, 0);font: 14pt \"微软雅黑\";")
        self.dock.setWidget(self.label)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.dock)

    def setCompleted(self):
        """
        完成后弹出游戏结果对话框
        """
        self.timer.stop()
        self.saveData.append(self.time)
        self.saveTime()
        info = "恭喜通关成功!用时:{}秒,继续努力吧!\n按下OK继续!".format(self.time)
        QMessageBox.information(self, "通过成功", info, QMessageBox.Ok)
        self.setupPuzzle()
        # 游戏完成后,我们的定时器会停止。保存当前游戏时间。弹出恭喜对话框。游戏重新初始化(setupPuzzle())

    def setupPuzzle(self):
        """
        游戏初始化
        """

        size = min(self.puzzleImage.width(), self.puzzleImage.height())
        #游戏图片尺寸

        self.puzzleImage = self.puzzleImage.copy(
            (self.puzzleImage.width() - size) / 2,
            (self.puzzleImage.height() - size) / 2, size,
            size).scaled(self.puzzleshow.width(), self.puzzleshow.height(),
                         Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
        #得到压缩尺寸后的图形

        if self.puzzlepiece.count() > 1:
            self.puzzlepiece.clear()
            #只有在当前拼图列表存在拼图的情况下才能清空列表

        for y in range(5):
            for x in range(5):
                pieceSize = self.puzzleshow.pieceSize()
                piece = self.puzzleImage.copy(x * pieceSize, y * pieceSize,
                                              pieceSize, pieceSize)
                self.puzzlepiece.addPiece(piece, QPoint(x, y))
        #切割图片并添加到列表中

        for i in range(self.puzzlepiece.count()):
            if random.random() * 10 > 3:
                item = self.puzzlepiece.takeItem(i)
                self.puzzlepiece.insertItem(0, item)
        #图片随机排序

        self.puzzleshow.clear()
        #还原的图形展示小部件清空

        self.setDock(self.puzzleImage)
        #完整的图形刷新

        self.time = 0
        self.timing()

    def loadTime(self):
        """
        载入游戏时间数据
        """
        pathname = "m.dat"

        if not (os.path.exists(pathname) and os.path.isfile(pathname)):
            data = [100000]
            with codecs.open("m.dat", "wb") as f:
                pickle.dump(data, f)

        with codecs.open("m.dat", "rb") as f:
            data = pickle.load(f)
        return data

    def saveTime(self):
        """
        保存游戏时间
        """
        with codecs.open("m.dat", "wb") as f:
            pickle.dump(self.saveData, f)

    def timing(self):
        """
        开始计时
        """
        self.timer = QTimer()
        self.timer.start(1000)
        self.timer.timeout.connect(self.second)

    def second(self):
        """
        显示游戏时间
        """
        self.time += 1
        timeinfo = "当前游戏用时:{}秒,最佳时间:{}秒".format(self.time, min(self.saveData))
        self.label.setText(timeinfo)

    def setDock(self, pix):
        """
        显示还原后的图片
        """
        label2 = QLabel()
        label2.setScaledContents(True)
        label2.setPixmap(pix)
        self.dock2.setWidget(label2)
        self.dock2.setFloating(True)

    @pyqtSlot()
    def on_action_O_triggered(self):
        """
        选择图片并开始游戏
        """
        fileName = QFileDialog.getOpenFileName(self, "打开文件", "./img",
                                               ("Images (*.png *.jpg)"))
        filepath = fileName[0]
        if filepath:
            self.puzzleImage = QPixmap(filepath)
            self.dock2.close()
            # 完成的拼图

            self.setupPuzzle()
            # 游戏初始化

            self.dock2.show()

            # 刷新一下这个画面,否则画面可能不会变
        else:
            QMessageBox.warning(self, "打开图片", "图片加载失败!", QMessageBox.Cancel)
            return

    @pyqtSlot()
    def on_action_E_triggered(self):
        """
        退出游戏
        """
        self.close()

    @pyqtSlot()
    def on_action_R_triggered(self):
        """
        重新开始游戏
        """
        self.setupPuzzle()

    @pyqtSlot()
    def on_action_P_triggered(self):
        """
        重新显示完成的图片
        """
        self.dock2.close()
        self.dock2.show()

    @pyqtSlot()
    def on_action_J_triggered(self):
        """
        关于
        """
        QMessageBox.information(self, "关于", "学点编程吧出品,必属精品!")
Ejemplo n.º 7
0
class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        #Инициализируем главное окно
        title = "Dulcis"
        top = 0
        left = 0
        width = 1900
        height = 1000

        self.setWindowTitle(title)
        self.setGeometry(top, left, width, height)
        self.setFixedSize(self.size())
        self.setWindowIcon(QIcon('donut.ico'))

        #Создаем пустое изображение, которое будем использовать в качестве холста
        self.image = QImage(self.size(), QImage.Format_RGB32)
        self.image.fill(Qt.white)
        self.isActiveWindow()

        self.drawing = False
        self.brushSize = 7
        self.brushColor = Qt.black
        self.lastPoint = QPoint()
        self.brush = None

        #Создаем док-виджет для изменения толщины грифеля карандаша
        self.dock = QDockWidget('Thickness')
        thickness = QSlider(Qt.Horizontal)
        thickness.setValue(7)
        thickness.setRange(3, 30)
        thickness.setTickInterval(1)
        thickness.setTickPosition(1)
        thickness.valueChanged.connect(self.thicknessChange)
        self.dock.setWidget(thickness)
        self.addDockWidget(Qt.TopDockWidgetArea, self.dock)
        self.dock.close()

        #Создаем главное меню и второстепенные, а также прописываем все действия при взаимодействии с элементами меню
        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu(QIcon("icons/file.png"), "")

        saveAction = QAction(QIcon("icons/save.ico"), "Save", self)
        saveAction.setShortcut("Ctrl+S")
        fileMenu.addAction(saveAction)
        saveAction.triggered.connect(self.save)

        clearAction = QAction(QIcon("icons/clear.png"), "Clear", self)
        clearAction.setShortcut("Ctrl+C")
        fileMenu.addAction(clearAction)
        clearAction.triggered.connect(self.clear)

        colorSet = QAction(QIcon("icons/palette.png"), "", self)
        colorSet.setShortcut("Ctrl+P")
        mainMenu.addAction(colorSet)
        colorSet.triggered.connect(self.selectColor)

        thickAction = QAction(QIcon("icons/thickness.png"), "", self)
        thickAction.setShortcut("Ctrl+T")
        mainMenu.addAction(thickAction)
        thickAction.triggered.connect(lambda: self.dock.show())

        eraserAction = QAction(QIcon("icons/eraser.jpg"), "", self)
        eraserAction.setShortcut("Ctrl+E")
        mainMenu.addAction(eraserAction)
        eraserAction.triggered.connect(self.eraser)

        cnvsMenu = mainMenu.addMenu(QIcon("icons/canvas.jpg"), "")
        changeCnvsColor = QAction("Change color", self)
        changeCnvsColor.setShortcut("Alt+C")
        cnvsMenu.addAction(changeCnvsColor)
        changeCnvsColor.triggered.connect(self.cnvsColor)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drawing = True
            self.lastPoint = event.pos()

    def mouseMoveEvent(self, event):
        if (event.buttons() & Qt.LeftButton) & self.drawing:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            painter.drawLine(self.lastPoint, event.pos())
            self.lastPoint = event.pos()
            self.update()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drawing = False

    def paintEvent(self, event):
        canvasPainter = QPainter(self)
        canvasPainter.drawImage(self.rect(), self.image, self.image.rect())

    def save(self):
        filePath, _ = QFileDialog.getSaveFileName(self, "Save Image", "",
                                                  "PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*) ")

        if filePath == "":
            return
        self.image.save(filePath)

    def clear(self):
        self.image.fill(Qt.white)
        self.update()

    def selectColor(self):
        self.brushColor = QColorDialog.getColor()

    def thicknessChange(self, value):
        self.brushSize = value

    def cnvsColor(self):
        self.image.fill(QColorDialog.getColor())

    def eraser(self):
        self.brushColor = Qt.white
Ejemplo n.º 8
0
class MediaPlayer(QMainWindow, Form):
    def __init__(self):
        Form.__init__(self)
        QMainWindow.__init__(self)
        self.setupUi(self)
        # Video Part
        self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.player.setVideoOutput(self.videowidget)
        self.setWindowTitle(" Media Player")
        self.setAcceptDrops(True)

        # Define some Events
        self.videowidget.mouseDoubleClickEvent = self.Doubleclick_mouse
        self.wheelEvent = self.Scroll_mouse
        self.mouseReleaseEvent = self.MainWindow_Event
        self.videowidget.mouseMoveEvent = self.MousePos
        self.resizeEvent = self.main_size_Change

        self.lineEdit_Bookmark.setVisible(False)
        self.lineEdit_Bookmark.returnPressed.connect(self.save_Bookmarks)

        # threads part
        self.tag_thread = None
        self.search_Thread = None
        self.SearchAnimation = None
        self.BookMarkAnimation = None

        # Create Tags
        self.allTag = {}
        self.tag_Path = None

        # create Volume Slide
        self.Slider_Volume = Slider(self)
        self.Slider_Volume.setOrientation(Qt.Horizontal)
        self.horizontalLayout_3.addWidget(self.Slider_Volume, 0)
        self.Slider_Volume.setMaximumWidth(100)
        self.Slider_Volume.setMaximumHeight(30)

        # create Play Slider
        self.Slider_Play = Slider(self)
        self.Slider_Play.setOrientation(Qt.Horizontal)
        self.Slider_Play.resize(644, 22)
        self.horizontalLayout_4.addWidget(self.label_Time)
        self.horizontalLayout_4.addWidget(self.Slider_Play)
        self.horizontalLayout_4.addWidget(self.label_Duration)

        # To Apply initial Theme
        self.Setting = Setting.SettingWindow(self)
        Theme_module.Theme_apply(self.Setting)

        #Create Help
        self.helpW = Help.helpWindow(self)

        # PushButttons
        self.pushButton_Start.setEnabled(False)
        self.pushButton_Start.clicked.connect(self.start)

        self.pushButton_volume.setEnabled(False)
        self.pushButton_volume.clicked.connect(self.volumeOnOff)

        self.pushButton_stop.setEnabled(False)
        self.pushButton_stop.clicked.connect(self.stop)
        self.pushButton_stop.setToolTip("Stop (Ctrl+Z)")

        self.pushButton_next.setEnabled(False)
        self.pushButton_next.clicked.connect(self.next)
        self.pushButton_next.setToolTip("Next (PgUp)")

        self.pushButton_previous.setEnabled(False)
        self.pushButton_previous.clicked.connect(self.previous)
        self.pushButton_previous.setToolTip("Previous (PgDn)")

        self.pushButton_open.clicked.connect(self.Load_video)
        self.pushButton_open.setToolTip("Open (Ctrl+O)")

        self.pushButton_Search.clicked.connect(self.sch_icon_Event)
        self.pushButton_Search.setToolTip("Search (Ctrl+S)")

        self.pushButton_BookMark.setVisible(False)
        self.pushButton_BookMark.clicked.connect(self.add_BookMarks)
        self.pushButton_BookMark.setToolTip("Add BookMark (Ctrl+B)")

        self.pushButton_Setting.clicked.connect(self.Settingshow)
        self.pushButton_Setting.setToolTip("Setting")

        self.pushButton_Playlist.clicked.connect(self.Play_list)
        self.pushButton_Playlist.setToolTip("Play list")
        self.PlaylistW = Playlist.PlaylistWindow(self)

        # Create Tags of file Dockwidget
        self.pushButton_Tag_of_file.clicked.connect(self.Show_Tags_of_file)
        self.pushButton_Tag_of_file.setToolTip("Tags of file")
        self.DockWidget_Tags_of_file = QDockWidget("Tags of file", self)
        self.DockWidget_Tags_of_file.setVisible(False)
        self.DockWidget_Tags_of_file.setMinimumWidth(150)
        self.ComboBox_Tags_of_file = QComboBox(self)
        self.ListWidget_Tags_of_file = QListWidget()
        widget = QWidget()  # Create Widget for Tags of file DockWidget
        layout = QVBoxLayout()  # Create Layout for Tags of file DockWidget
        # Add Listwiget and ComboBox to layout
        layout.addWidget(self.ComboBox_Tags_of_file)
        layout.addWidget(self.ListWidget_Tags_of_file)
        widget.setLayout(layout)  # Set layout on the widget
        # set Widget on Tags of file DockWidget
        self.DockWidget_Tags_of_file.setWidget(widget)
        self.addDockWidget(Qt.RightDockWidgetArea,
                           self.DockWidget_Tags_of_file)
        self.ComboBox_Tags_of_file.activated.connect(self.ListWidget_Tag)
        self.ListWidget_Tags_of_file.itemActivated.connect(self.GoToTagtime)

        # Slider Play
        self.Slider_Play.setRange(0, 0)
        self.player.positionChanged.connect(self.Position_changed)
        self.player.durationChanged.connect(self.Duration_changed)
        self.Slider_Play.setUP_Slider.connect(self.Set_Position)
        self.Slider_Play.moveMent_Position.connect(self.slider_play_pos)

        # Label Time
        self.Slider_play_label = QLabel("Time", parent=self)
        self.Slider_play_label.resize(50, 20)
        self.Slider_play_label.setAlignment(Qt.AlignCenter)
        self.Slider_play_label.setVisible(False)

        # Slider Volume
        self.Slider_Volume.setRange(0, 0)
        self.Slider_Volume.setUP_Slider.connect(self.Set_volume)
        self.Slider_Volume.moveMent_Position.connect(self.slider_volume_pos)

        # Label Volume
        self.Slider_Volume_label = QLabel("Volume", parent=self)
        self.Slider_Volume_label.resize(30, 20)
        self.Slider_Volume_label.setAlignment(Qt.AlignCenter)
        self.Slider_Volume_label.setVisible(False)

        # Create listWidget for search part
        self.sch_listWidget = QListWidget(self)
        self.sch_listWidget.setVisible(False)
        self.search_lineEdit.setVisible(False)
        # Search signals
        self.sch_listWidget.itemDoubleClicked.connect(
            self.item_searchlist_Event)
        self.search_lineEdit.textChanged.connect(self.search_Tag)

        # Define Action for Tool Bar
        self.actionOpen.triggered.connect(self.Load_video)
        self.actionChange_Password.triggered.connect(self.menuBarAccout)
        self.actionDelete_Account.triggered.connect(self.menuBarAccout)

        self.actionHelp.triggered.connect(self.Help)
        self.actionLogOut.triggered.connect(self.Logout)
        self.actionExit.triggered.connect(lambda: self.close())

        self.actionFullScreen.triggered.connect(self.fullscreen)
        self.actionSpeed.triggered.connect(self.menuBarSpeed)
        self.actionThme.triggered.connect(self.menuBarTheme)

        self.actionCreate_Tag.triggered.connect(self.menuBarCreateTag)
        self.actionOpen_Tags.triggered.connect(self.openTags)
        self.actionEdit_Tag.triggered.connect(self.menuBarEditTag)
        self.actionClose_Tag.triggered.connect(self.menuBarCloseTag)

        # Shortcut
        QShortcut(QKeySequence('Ctrl+B'),
                  self).activated.connect(self.add_BookMarks)
        QShortcut(QKeySequence('Ctrl+Z'), self).activated.connect(self.stop)
        QShortcut(QKeySequence('Ctrl+M'),
                  self).activated.connect(self.volumeOnOff)
        QShortcut(QKeySequence('Ctrl+S'),
                  self).activated.connect(self.sch_icon_Event)
        QShortcut(QKeySequence('Ctrl+O'),
                  self).activated.connect(self.Load_video)

        # For FullScreen part
        self.firstTime_fullscreen = True

        # close event to stop running thread
        self.closeEvent = self.Close

    # KeyPress Event
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_PageDown and self.pushButton_next.isEnabled():
            self.next()
        if event.key() == Qt.Key_PageUp and self.pushButton_previous.isEnabled(
        ):
            self.previous()
        if event.key() == Qt.Key_F5:
            self.fullscreen()
        if event.key() == Qt.Key_6:
            self.Move_Slider_play(self.width() * 4500 / self.player.duration())
        if event.key() == Qt.Key_4:
            self.Move_Slider_play(
                (-1 * self.width() * 4500 / self.player.duration()))
        if event.key() == Qt.Key_8:
            self.Move_Slider_volume(+1)
        if event.key() == Qt.Key_2:
            self.Move_Slider_volume(-1)

    def menuBarTheme(self):
        # Open Theme Tab of Setting Window
        self.Setting.Account_changing = False
        self.Settingshow()
        self.Setting.Tab.setCurrentIndex(0)

    def Help(self):
        self.helpW.show()

    def menuBarSpeed(self):
        # Open Speed Tab of Setting Window
        self.Setting.Account_changing = False
        self.Settingshow()
        self.Setting.Tab.setCurrentIndex(1)

    def menuBarEditTag(self):
        # Open Tag Tab of Setting Window
        self.Setting.Account_changing = False
        self.Settingshow()
        self.Setting.Tab.setCurrentIndex(2)

    def menuBarAccout(self):
        # Open Account Tab of Setting Window
        self.Setting.Account_changing = False
        self.Settingshow()
        self.Setting.Tab.setCurrentIndex(3)

    def menuBarCreateTag(self):
        # create new Tag file
        if self.tag_Path:
            self.confirmCloseTag = confrimWin(
                self,
                Title="Create Tag",
                Text="Are you sure to close current tag and create new one")
            self.actionCreate_Tag.setEnabled(False)
            self.confirmCloseTag.show()
        else:
            dialog = QFileDialog(self, 'File tag', directory=os.getcwd())
            _path = dialog.getSaveFileName(filter="*.csv")[0]
            try:
                if _path:
                    self.tag_Path = _path
                    open(self.tag_Path, "w")
            except:
                pass

    def menuBarCloseTag(self):
        # close current tags
        if self.tag_Path:
            self.confirmCloseTag = confrimWin(
                self,
                Title="Close Tag",
                Text="Are you sure to close current tag")
            self.confirmCloseTag.show()
            self.actionClose_Tag.setEnabled(False)
        else:
            self.confirmCloseTag = confrimWin(self,
                                              Title="Warning",
                                              Text="There is no tag to close")
            self.confirmCloseTag.show()
            self.actionClose_Tag.setEnabled(False)

    def fullscreen(self):
        self.DockWidget_Tags_of_file.setVisible(False)
        self.Slider_play_label.setVisible(False)
        self.Slider_Volume_label.setVisible(False)

        Full_screen.fullscreen(self)

    # Define some Events
    def MousePos(self, position):
        if self.isFullScreen():
            Full_screen.MousePosition(self, position)
        self.Slider_play_label.setVisible(False)
        self.Slider_Volume_label.setVisible(False)

    def Doubleclick_mouse(self, position):
        if self.pushButton_Start.isEnabled():
            self.start()

    def Scroll_mouse(self, event):
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            self.Set_volume(
                int(self.player.volume() + event.angleDelta().y() / 120))

    def Move_Slider_play(self, move):
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            Now = self.player.position() * self.Slider_Play.width(
            ) / self.player.duration()
            self.Set_Position(Now + move)

    def Move_Slider_volume(self, move):
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            self.Set_volume(self.player.volume() + move)

    def Settingshow(self):
        # To show Setting window
        self.Setting.Tab.setCurrentIndex(0)
        self.Setting.lineEdit_CurrentPass.clear()
        self.Setting.lineEdit_NewPass.clear()
        self.Setting.lineEdit_ReNewpass.clear()
        self.Setting.label_finish.setVisible(False)
        self.Setting.label_NotMatch.setVisible(False)
        self.Setting.label_PassLong.setVisible(False)
        self.Setting.label_OldPass.setVisible(False)
        self.Setting.label_Wait.setVisible(False)
        self.Setting.label_Error.setVisible(False)
        self.Setting.Account_changing = False
        self.Setting.show()

    def start(self):
        # Start and Pause the player
        if self.player.state() == QMediaPlayer.PlayingState:  # Stop
            self.player.pause()
            self.pushButton_Start.setEnabled(True)
            self.pushButton_Start.setIcon(QIcon('./Icons/play.png'))
            self.pushButton_Start.setToolTip("Play")

        else:  # Start
            self.player.play()
            self.pushButton_Start.setEnabled(True)
            self.pushButton_Start.setIcon(QIcon('./Icons/pause.png'))
            self.pushButton_Start.setToolTip("Pause")
        self.pushButton_Start.setFocus(True)

    def stop(self):
        # Stop player
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            self.player.stop()
            self.pushButton_next.setEnabled(False)
            self.pushButton_previous.setEnabled(False)
            self.pushButton_volume.setEnabled(False)
            self.pushButton_Start.setEnabled(False)
            self.pushButton_stop.setEnabled(False)
            self.pushButton_BookMark.setVisible(False)
            self.label_Duration.setText("00:00:00")
            self.label_Time.setText("00:00:00")
            self.Slider_Volume.setEnabled(False)

    def next(self):
        # Play next file from playlist
        # If the playing file is in the playlist
        if self.windowTitle()[16:] in self.PlaylistW.Files.keys():
            self.PlaylistW.listWidget_Playlist.setCurrentRow(
                list(self.PlaylistW.Files.keys()).index(self.windowTitle()
                                                        [16:]) + 1)
        else:  # If the playing file is not in the playlist
            self.PlaylistW.listWidget_Playlist.setCurrentRow(
                self.PlaylistW.listWidget_Playlist.currentRow() + 1)

        self.PlaylistW.spliter = len(
            str(self.PlaylistW.listWidget_Playlist.currentRow() + 1)) + 3
        self.player.setMedia(
            QMediaContent(
                QUrl.fromLocalFile(self.PlaylistW.Files[
                    self.PlaylistW.listWidget_Playlist.currentItem().text()
                    [self.PlaylistW.spliter:]])))
        # Change title
        self.setWindowTitle(
            f" Media Player - {self.PlaylistW.listWidget_Playlist.currentItem().text()[self.PlaylistW.spliter:]}"
        )
        currentText = self.PlaylistW.listWidget_Playlist.currentItem().text(
        )[self.PlaylistW.spliter:]
        index = self.ComboBox_Tags_of_file.findText(currentText)
        self.ComboBox_Tags_of_file.setCurrentIndex(index)
        self.set_TagonListwidget(".".join(currentText.split(".")[:-1]))
        self.start()
        # To handle Next button
        if self.PlaylistW.listWidget_Playlist.currentRow(
        ) == self.PlaylistW.listWidget_Playlist.count() - 1:
            self.pushButton_next.setEnabled(False)

        self.pushButton_previous.setEnabled(True)

    def previous(self):
        # Play previous file from playlist
        # If the playing file is in the playlist
        if self.windowTitle()[16:] in self.PlaylistW.Files.keys():
            self.PlaylistW.listWidget_Playlist.setCurrentRow(
                list(self.PlaylistW.Files.keys()).index(self.windowTitle()
                                                        [16:]) - 1)
        else:  # If the playing file is not in the playlist
            self.PlaylistW.listWidget_Playlist.setCurrentRow(
                self.PlaylistW.listWidget_Playlist.currentRow())

        self.PlaylistW.spliter = len(
            str(self.PlaylistW.listWidget_Playlist.currentRow() + 1)) + 3

        self.player.setMedia(
            QMediaContent(
                QUrl.fromLocalFile(self.PlaylistW.Files[
                    self.PlaylistW.listWidget_Playlist.currentItem().text()
                    [self.PlaylistW.spliter:]])))
        self.setWindowTitle(
            f" Media Player - {self.PlaylistW.listWidget_Playlist.currentItem().text()[self.PlaylistW.spliter:]}"
        )
        currentText = self.PlaylistW.listWidget_Playlist.currentItem().text(
        )[self.PlaylistW.spliter:]
        index = self.ComboBox_Tags_of_file.findText(currentText)
        self.ComboBox_Tags_of_file.setCurrentIndex(index)
        self.set_TagonListwidget(".".join(currentText.split(".")[:-1]))
        self.start()

        # To handle previous button
        if not self.PlaylistW.listWidget_Playlist.currentRow():
            self.pushButton_previous.setEnabled(False)
        self.pushButton_next.setEnabled(True)

    def Load_video(self, filepath=None):
        # Load Files of directory
        # just mp4 ,mkv , mp3
        if not filepath:
            try:
                # To read initial Directory from csvfile
                with open("./PlayListPart/Filepath.csv") as file:
                    initial_FilePath = file.read()
                    file_path, _ = QFileDialog.getOpenFileName(
                        self,
                        "Open video",
                        directory=initial_FilePath,
                        filter='*.mp4 *.mkv *.mp3')
            except:
                initial_FilePath = os.getcwd()
                file_path, _ = QFileDialog.getOpenFileName(
                    self,
                    "Open video",
                    directory=initial_FilePath,
                    filter='*.mp4 *.mkv *.mp3')
        else:
            initial_FilePath = None
            file_path = filepath
        if file_path:
            # To write initial Directory in csvfile
            if file_path.replace(file_path.split("/")[-1],
                                 "") != initial_FilePath:
                with open("./PlayListPart/Filepath.csv", 'w') as file:
                    file.write(file_path.replace(file_path.split("/")[-1], ""))
            self.player.setMedia(QMediaContent(QUrl.fromLocalFile(file_path)))
            self.start()
            self.pushButton_volume.setEnabled(True)
            self.pushButton_volume.setIcon(QIcon('./Icons/unmute.png'))
            self.pushButton_volume.setToolTip("Mute (Ctrl+M)")
            if not self.isFullScreen():
                self.pushButton_BookMark.setVisible(True)
            self.pushButton_stop.setEnabled(True)
            # Handle Volume Slider
            self.Slider_Volume.setEnabled(True)
            self.Slider_Volume.setRange(0, self.player.volume())
            self.Slider_Volume.setValue(60)
            self.player.setVolume(60)

            # Create Playlist
            self.Setting.comboBox_Tag.clear()
            self.ComboBox_Tags_of_file.clear()
            self.PlaylistW.Create_Playlist(file_path)
            self.set_TagonListwidget(".".join(
                self.windowTitle()[16:].split(".")[:-1]))

    def Position_changed(self, position):
        if position > self.player.duration():
            position = self.player.duration()
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            hour = position // (1000 * 3600)
            minute = (position % (1000 * 3600)) // (60 * 1000)
            second = ((position % (1000 * 3600)) % (60 * 1000)) // 1000
            # Show Time
            self.label_Time.setText(
                f'{str(hour).zfill(2)}:{str(minute).zfill(2)}:{str(second).zfill(2)}'
            )
        # Automatic Next
        if self.player.duration() and position == self.player.duration():
            if self.pushButton_next.isEnabled():
                self.next()
            else:
                self.stop()
        self.Slider_Play.setValue(position)

    def Duration_changed(self, duration):
        # To set file duration
        self.Slider_Play.setRange(0, duration)
        # convert millsec to xx:xx:xx format
        hour = duration // (1000 * 3600)
        minute = (duration % (1000 * 3600)) // (60 * 1000)
        second = ((duration % (1000 * 3600)) % (60 * 1000)) // 1000
        self.label_Duration.setText(
            f'{str(hour).zfill(2)}:{str(minute).zfill(2)}:{str(second).zfill(2)}'
        )

        self.Slider_Volume.setEnabled(True)

    def Set_Position(self, position):
        if self.Slider_Play.width() - 1 <= position:
            position = self.Slider_Play.width() - 1
            self.player.pause()
            self.pushButton_Start.setEnabled(True)
            self.pushButton_Start.setIcon(QIcon('./Icons/play.png'))
            self.pushButton_Start.setToolTip("Paly")

        # if not (position < 0 and position > self.Slider_Play.width()):
        position = int(self.player.duration() *
                       (position / self.Slider_Play.width()))
        self.Slider_Play.setValue(position)
        self.player.setPosition(position)

    def slider_play_pos(self, position):
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            # Convert Width of Slider to time
            Time = int(self.player.duration() * position /
                       self.Slider_Play.width())
            # convert millsec to xx:xx:xx format
            hour = Time // (1000 * 3600)
            minute = (Time % (1000 * 3600)) // (60 * 1000)
            second = ((Time % (1000 * 3600)) % (60 * 1000)) // 1000
            self.Slider_play_label.setText(
                f'{str(hour).zfill(2)}:{str(minute).zfill(2)}:{str(second).zfill(2)}'
            )
            if self.isFullScreen():
                self.Slider_play_label.move(position + self.Slider_Play.x(),
                                            self.height() - 65)
            else:
                self.Slider_play_label.move(position + self.Slider_Play.x(),
                                            self.height() - 80)
            self.Slider_play_label.setVisible(True)

    def slider_volume_pos(self, position):
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            # Convert Width of Slider to volume
            volume = int(100 * position / self.Slider_Volume.width())
            self.Slider_Volume_label.setText(f'{volume}%')
            if self.isFullScreen():
                self.Slider_Volume_label.move(
                    position + self.Slider_Volume.x() - 5,
                    self.height() - 37)
            else:
                self.Slider_Volume_label.move(
                    position + self.Slider_Volume.x() - 5,
                    self.height() - 48)
            self.Slider_Volume_label.setVisible(True)

    def Set_volume(self, volume):
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            # Volume must be between 0 , 100
            if 100 <= volume:
                volume = 100
            elif volume <= 0:
                volume = 0

            if not volume:
                self.player.setMuted(True)
                self.pushButton_volume.setIcon(QIcon('./Icons/mute.png'))
                self.pushButton_volume.setToolTip("UnMute (Ctrl+M)")

            else:
                self.player.setMuted(False)
                self.pushButton_volume.setIcon(QIcon('./Icons/unmute.png'))
                self.pushButton_volume.setToolTip("Mute (Ctrl+M)")

            self.Slider_Volume.setValue(volume)
            self.player.setVolume(volume)

    def volumeOnOff(self):
        """Mute and unmute"""
        if self.player.isAudioAvailable() or self.player.isVideoAvailable():
            if self.player.isMuted():
                self.player.setMuted(False)
                self.pushButton_volume.setIcon(QIcon('./Icons/unmute.png'))
                self.pushButton_volume.setToolTip("Mute (Ctrl+M)")
            else:
                self.player.setMuted(True)
                self.pushButton_volume.setIcon(QIcon('./Icons/mute.png'))
                self.pushButton_volume.setToolTip("UnMute (Ctrl+M)")

    # save bookmarks and updatae tag list widget
    def save_Bookmarks(self):
        if not self.tag_Path:
            error_addBookmark = confrimWin(
                self,
                Title="Warning",
                Text="First select or create a tag file and try again")
            error_addBookmark.show()
            return False
        try:
            # use add bookmark function to add bookmarks in tag part
            add_Bookmark(
                self.lineEdit_Bookmark.text() + "#" +
                tc.millis_to_format(self.player.position()),
                ".".join(self.windowTitle()[16:].split(".")[:-1]),
                self.tag_Path)
            # there isn't any tags for movie we want to add bookmark it
            if not ".".join(
                    self.windowTitle()[16:].split(".")[:-1]) in self.allTag:
                self.allTag.update(
                    {".".join(self.windowTitle()[16:].split(".")[:-1]): {}})
            self.allTag[".".join(
                self.windowTitle()[16:].split(".")[:-1])].update({
                    self.lineEdit_Bookmark.text():
                    tc.millis_to_format(self.player.position())
                })
            self.set_TagonListwidget(
                self.windowTitle()[16:].split(".")[0])  # update tag listwidget
            # update combo box of edit and Main window
            self.pushButton_Start.setFocus(True)
            index = self.ComboBox_Tags_of_file.findText(
                self.windowTitle()[16:])
            self.ComboBox_Tags_of_file.setCurrentIndex(index)
            index = self.Setting.comboBox_Tag.findText(self.windowTitle()[16:])
            self.Setting.comboBox_Tag.setCurrentIndex(index)
            # ****

        except:
            pass

        self.lineEdit_Bookmark.clear()
        self.lineEdit_Bookmark.setVisible(False)

    def sch_icon_Event(self):
        # Show search lineEdit to search
        self.search_lineEdit.setFixedWidth(0)

        # Start Animation of search lineEdit
        self.SearchAnimation = Search_Animation(self)
        self.SearchAnimation.update_Animation.connect(
            self.Update_Search_Animation)
        self.pushButton_Search.setEnabled(False)
        self.SearchAnimation.start()

        self.search_lineEdit.setVisible(True)
        self.search_lineEdit.setFocus(True)

    def Update_Search_Animation(self, size):
        if size == -1:  # Animation is finished
            self.pushButton_Search.setEnabled(True)
        else:  # Animation is running
            self.search_lineEdit.setFixedWidth(size)

    def add_BookMarks(self):
        # Show Bookmark lineEdit to search

        if self.player.isVideoAvailable() or self.player.isAudioAvailable():
            self.lineEdit_Bookmark.setFixedWidth(0)

            # Start Animation of search lineEdit
            self.BookMarkAnimation = BookMark_Animation(self)
            self.BookMarkAnimation.update_Animation.connect(
                self.Update_BookMark_Animation)

            self.pushButton_BookMark.setEnabled(False)
            self.BookMarkAnimation.start()

            self.lineEdit_Bookmark.setVisible(True)
            self.lineEdit_Bookmark.setFocus(True)

    def Update_BookMark_Animation(self, size):
        if size == -1:  # Animation is finished
            self.pushButton_BookMark.setEnabled(True)
        else:  # Animation is running
            self.lineEdit_Bookmark.setFixedWidth(size)

    def MainWindow_Event(self, type):
        # Click on MainWindow
        self.search_lineEdit.setText("")
        self.search_lineEdit.setVisible(False)

        self.lineEdit_Bookmark.setText("")
        self.lineEdit_Bookmark.setVisible(False)

        self.sch_listWidget.setVisible(False)
        self.sch_listWidget.clear()

    # handle main size change to set correct size to
    # search and bookmark line edits and searchlistwidgetd
    def main_size_Change(self, val):
        self.lineEdit_Bookmark.setFixedWidth(int(self.size().width() / 4))
        self.search_lineEdit.setFixedWidth(int(self.size().width() / 4))

        self.sch_listWidget.resize(  # Handle size of search listwidget
            int(self.size().width() / 4),
            int((200 / 600) * self.size().height()))
        self.sch_listWidget.move(  # Move search listwidget
            self.size().width() - self.pushButton_Search.geometry().width() -
            self.search_lineEdit.geometry().width() - 15,
            self.search_lineEdit.geometry().height() +
            self.search_lineEdit.pos().y() + self.menubar.geometry().height())

    # Item clicked event in search tag part
    def item_searchlist_Event(self, item):
        session, tag = re.split(" -> ", item.text())
        # get all session to compare that is selected tag in playlist or user select tag wrong
        all_sessions = list(self.PlaylistW.Files.keys())
        # there is bug here if mp3 and mp4 has same name
        all_sessions = [
            ".".join(item.split(".")[:-1]) for item in all_sessions
        ]
        if session in all_sessions:
            if session != ".".join(self.windowTitle()[16:].split(".")[:-1]):
                # Show confirm window to get accept user for change video
                self.confirmWin = confrimWin(
                    self,
                    session=session,
                    tag_Text=tag,
                    Text=
                    f"Are you sure to change video to {session} from search")
                self.confirmWin.show()
            else:
                try:
                    # concert time format to second for using in change position
                    time_second = tc.to_second(self.allTag[session][tag])
                    self.change_Position(time_second)
                except:  # handle unexcepted error!
                    pass
        else:
            Warning_user_wrongTags = confrimWin(
                self, Title="Warning", Text="You have opened wrong tag files")
            Warning_user_wrongTags.show()

    # Create search listwidget and running thread to starting search

    def search_Tag(self, val):
        # Create QListWidget
        self.sch_listWidget.resize(int((200 / 800) * self.size().width()),
                                   int((200 / 600) * self.size().height()))
        self.sch_listWidget.move(
            self.search_lineEdit.x(),
            self.search_lineEdit.geometry().height() +
            self.search_lineEdit.pos().y() + self.menubar.geometry().height())

        self.sch_listWidget.setVisible(True)
        if val == "":
            self.sch_listWidget.clear()
        # start search thread
        else:
            self.search_Thread = search_thread(self, self.allTag, val)
            self.search_Thread.update_schTag.connect(self.update_searchTags)
            self.search_Thread.start()

    # Update searchtags function to update search widget by searching instantly
    def update_searchTags(self, tagsDict):
        self.sch_listWidget.clear()  # clear search list widget

        for session, Tags in tagsDict.items(
        ):  # writing data on search listwidget
            for text in Tags:
                self.sch_listWidget.addItem(session + " -> " + text)

    def Logout(self):
        os.remove("LoginPart/User.csv")
        self.close()
        self.player.stop()
        self.Setting.close()
        self.PlaylistW.close()
        self.helpW.close()
        self.DockWidget_Tags_of_file.close()
        subprocess.call(['python', 'MediaPlayer.py'])  # Start again

    def Play_list(self):
        # Open playlist
        # To show current Row for every time it is opened

        try:
            if self.PlaylistW.listWidget_Playlist.count():
                self.PlaylistW.listWidget_Playlist.setCurrentRow(
                    list(self.PlaylistW.Files.keys()).index(
                        self.windowTitle()[16:]))
        except Exception as e:
            pass

        self.PlaylistW.show()
        # setPosition of playlist when it is opened
        self.PlaylistW.move(
            QtGui.QCursor().pos().x(),
            QtGui.QCursor().pos().y() - self.PlaylistW.size().height() - 25)

    def Show_Tags_of_file(self):
        self.sch_listWidget.setVisible(False)
        # To show Tags of file in DockWidget
        self.DockWidget_Tags_of_file.setVisible(
            not self.DockWidget_Tags_of_file.isVisible())
        index = self.ComboBox_Tags_of_file.findText(self.windowTitle()[16:])
        self.ComboBox_Tags_of_file.setCurrentIndex(index)
        # To Change features of the Dockwidget according Fullscreen
        if self.isFullScreen():
            self.DockWidget_Tags_of_file.setFeatures(
                QDockWidget.DockWidgetClosable)
            Full_screen.Set_visible(self, False)

        else:  # To Change features of the Dockwidget according Normalscreen
            self.DockWidget_Tags_of_file.setFeatures(
                QDockWidget.DockWidgetFloatable
                | QDockWidget.DockWidgetMovable)

    def ListWidget_Tag(self, index):
        """Tag combo box item clicked function"""
        videoName = ".".join(
            list(self.PlaylistW.Files.keys())[index].split(".")[:-1])
        self.set_TagonListwidget(videoName, Setting_Tags=False)

    def openTags(self):
        """OpenTag in csv, pptx, docx format and start tag thread for reading data"""
        try:
            # To read initial Tag Directory from csvfile
            # if there is FilePath_Tag.csv
            with open("./tagPart/Filepath_Tag.csv") as file:
                initial_FilePath_Tag = file.read()
                _tag_Path, _ = QFileDialog.getOpenFileName(
                    self,
                    "Open Tag",
                    directory=initial_FilePath_Tag,
                    filter='*.csv *.docx *.pptx')

        except Exception as e:
            initial_FilePath_Tag = os.path.join(os.getcwd(), 'Tags')
            _tag_Path, _ = QFileDialog.getOpenFileName(
                self,
                "Open Tag",
                directory=initial_FilePath_Tag,
                filter='*.csv *.docx *.pptx')

        # if tagpath is correct we starting tag_thread to read tags from path
        if _tag_Path:
            # save filepath in csv file
            self.tag_Path = _tag_Path
            try:
                with open("./tagPart/Filepath_Tag.csv", 'w') as file:
                    file.write(
                        self.tag_Path.replace(
                            self.tag_Path.split("/")[-1], ""))
            except Exception as e:
                pass
            Tagname = self.tag_Path.split("/")[-1]
            fileFormat = Tagname.split(".")[-1]
            self.tag_thread = read_Tag(self, self.tag_Path, fileFormat)
            self.tag_thread.Tag_Ready.connect(self.getTag)
            self.tag_thread.start()

    # Tag is ready to use
    # if tags ready we shoud save them in self.allTag variable to use them properly
    def getTag(self, tags):
        self.allTag = tags
        index = self.ComboBox_Tags_of_file.findText(self.windowTitle()[16:])
        self.ComboBox_Tags_of_file.setCurrentIndex(index)
        self.set_TagonListwidget(".".join(
            self.windowTitle()[16:].split(".")[:-1]))

    # set tags on tag listwidget using vedio name
    # update tags

    def set_TagonListwidget(self,
                            videoName,
                            Setting_Tags=True,
                            Media_Tags=True):
        if Media_Tags:
            self.ListWidget_Tags_of_file.clear()
        if Setting_Tags:
            self.Setting.Edit_tag_Listwidget.clear()
        try:
            if videoName in self.allTag:
                sessionTag = self.allTag[videoName]
                # sorted tags by time
                sessionTag = {
                    text: time
                    for text, time in sorted(
                        sessionTag.items(),
                        key=lambda item: tc.to_second(item[1]))
                }
                for text in sessionTag:
                    # setting part tags by qtreewidget
                    if Setting_Tags:
                        item = QTreeWidgetItem(
                            self.Setting.Edit_tag_Listwidget,
                            [text, sessionTag[text]])
                    # media part tags by qlistwidget
                    if Media_Tags:
                        self.ListWidget_Tags_of_file.addItem(
                            f'{self.ListWidget_Tags_of_file.count()+1} . {text}'
                        )

        except:
            pass

    # item clicked event to go to time correlate clicked tag in video

    # change time when clicking on tags in search part and main listwidget if tags

    def GoToTagtime(self, item):
        spliter = len(str(self.ListWidget_Tags_of_file.currentRow() + 1)) + 3
        tag_Text = item.text()[spliter:]
        # change time if clicked on tags that belong to playing session
        if self.windowTitle()[16:] == self.ComboBox_Tags_of_file.currentText():
            session = ".".join(self.windowTitle()[16:].split(".")[:-1])
            try:
                # convert time to seconds using tc mudole(write by own)
                time_second = tc.to_second(self.allTag[session][tag_Text])
                # using change position function to handle sliders and time
                self.change_Position(time_second)
            except:
                pass
        else:
            session = ".".join(
                self.ComboBox_Tags_of_file.currentText().split(".")[:-1])
            self.confirmWin = confrimWin(
                self,
                session=session,
                tag_Text=tag_Text,
                Text=f"Are you sure to change video to {session}")
            self.confirmWin.show()

    def change_Position(self, time_second):
        # change slider position using item time
        self.Slider_Play.setValue(int(time_second) * 1000)
        # change video position using item time
        self.player.setPosition(int(time_second) * 1000)

    # change video function to change video when clicked on
    # tags that there is not in current movie's tags

    def change_Video(self, session):
        # there is bug here if user select mp3 file that has same name with mp4 similar file
        for key in self.PlaylistW.Files:
            if session + ".mp4" == key:
                return self._change_Video(key)
            elif session + ".mp3" == key:
                return self._change_Video(key)
            elif session + ".mkv" == key:
                return self._change_Video(key)
        return False

    def _change_Video(self, key):
        self.player.setMedia(
            QMediaContent(QUrl.fromLocalFile(
                self.PlaylistW.Files[key])))  # set video
        self.start()
        self.setWindowTitle(f" Media Player - {key}")  # change title
        # update combo box of session in MediaPlayer
        index = self.ComboBox_Tags_of_file.findText(key)
        self.ComboBox_Tags_of_file.setCurrentIndex(index)  # update combo box
        # update tags on setting and MediaPlayer window
        self.set_TagonListwidget(".".join(key.split(".")[:-1]))
        return True

    # close Event to stop runnig thread and preventing error
    def Close(self, val):
        if self.tag_thread:
            self.tag_thread.stop()
        if self.search_Thread:
            self.search_Thread.stop()
        if self.SearchAnimation:
            self.SearchAnimation.stop()
        if self.BookMarkAnimation:
            self.BookMarkAnimation.stop()

    # dragEnterEvent to hanle drag and drop option

    def dragEnterEvent(self, event):
        # pass
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    # dragMoveEvent to hanle drag and drop option
    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    # dropEvent to hanle drag and drop option
    def dropEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(Qt.CopyAction)
            # get droppen file path
            file_path = event.mimeData().urls()[0].toLocalFile()
            file_format = (file_path.split("/")[-1]).split(".")[-1]
            desired_format = ['mp4', 'mkv', 'mp3']  # desired path to open
            if file_format in desired_format:  # check file format
                self.Load_video(filepath=file_path)