コード例 #1
0
ファイル: ui.py プロジェクト: samirashoi/FeelUOwn
class PlayerControlPanel(QFrame):
    def __init__(self, app, parent=None):
        super().__init__(parent)
        self._app = app

        class IconButton(QPushButton):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                # 按钮文字一般是一个 symbol,长度控制为 40 是满足需求的
                self.setMaximumWidth(40)

        self._playback_modes = list(PlaybackMode.__members__.values())
        self._pm_alias_map = {
            PlaybackMode.one_loop: '单曲循环',
            PlaybackMode.sequential: '顺序播放',
            PlaybackMode.loop: '循环播放',
            PlaybackMode.random: '随机播放',
        }

        # initialize sub widgets
        self._layout = QHBoxLayout(self)
        self.previous_btn = IconButton(self)
        self.pp_btn = IconButton(self)
        self.next_btn = IconButton(self)
        self.pms_btn = QPushButton(self)
        self.volume_btn = VolumeButton(self)
        self.volume_btn.change_volume_needed.connect(
            lambda volume: setattr(self._app.player, 'volume', volume))
        self.playlist_btn = IconButton(parent=self)

        self.previous_btn.setObjectName('previous_btn')
        self.pp_btn.setObjectName('pp_btn')
        self.next_btn.setObjectName('next_btn')
        self.playlist_btn.setObjectName('playlist_btn')
        self.volume_btn.setObjectName('volume_btn')
        self.pms_btn.setObjectName('pms_btn')

        self.progress_slider = ProgressSlider(self)

        # TODO(simple): implementation
        self.pms_btn.setToolTip('修改播放模式(未实现,欢迎 PR)')
        self.volume_btn.setToolTip('调整音量(未实现,欢迎 PR)')
        self.playlist_btn.setToolTip('显示当前播放列表')
        self.progress_slider.setToolTip('拖动调节进度(未实现,欢迎 PR)')

        if not use_mac_theme():
            self.previous_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaSkipBackward))
            self.pp_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
            self.next_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaSkipForward))
            self.volume_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaVolume))
            self.playlist_btn.setText('🎶')
        else:
            self.pp_btn.setCheckable(True)

        self.song_title_label = QLabel('No song is playing.', parent=self)
        self.song_title_label.setAlignment(Qt.AlignCenter)
        self.duration_label = QLabel('00:00', parent=self)
        self.position_label = QLabel('00:00', parent=self)

        self.next_btn.clicked.connect(self._app.player.play_next)
        self.previous_btn.clicked.connect(self._app.player.play_previous)
        self.pp_btn.clicked.connect(self._app.player.toggle)
        self.pms_btn.clicked.connect(self._switch_playback_mode)

        self._app.player.state_changed.connect(self._on_player_state_changed)
        self._app.player.playlist.playback_mode_changed.connect(
            self.on_playback_mode_changed)
        self._app.player.playlist.song_changed.connect(
            self.on_player_song_changed)
        self.progress_slider.resume_player_needed.connect(
            self._app.player.resume)
        self.progress_slider.pause_player_needed.connect(
            self._app.player.pause)
        self.progress_slider.change_position_needed.connect(
            lambda value: setattr(self._app.player, 'position', value))

        self._update_pms_btn_text()
        self._setup_ui()

    def _setup_ui(self):
        # set widget layout
        self.progress_slider.setMinimumWidth(480)
        self.progress_slider.setMaximumWidth(600)
        self.progress_slider.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Preferred)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self._sub_layout = QVBoxLayout()
        self._sub_layout.addWidget(self.song_title_label)
        self._sub_layout.addWidget(self.progress_slider)

        self._layout.addSpacing(20)
        self._layout.addWidget(self.previous_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.pp_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.next_btn)
        self._layout.addSpacing(26)
        self._layout.addWidget(self.volume_btn)
        self._layout.addStretch(0)
        self._layout.addWidget(self.position_label)
        self._layout.addSpacing(7)
        self._layout.addLayout(self._sub_layout)
        self._layout.addSpacing(7)
        self._layout.addWidget(self.duration_label)
        self._layout.addSpacing(5)
        self._layout.addStretch(0)
        self._layout.addWidget(self.pms_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.playlist_btn)
        self._layout.addSpacing(18)

        self._layout.setSpacing(0)
        self._layout.setContentsMargins(0, 0, 0, 0)

    def _switch_playback_mode(self):
        playlist = self._app.player.playlist
        pm_total = len(self._playback_modes)
        pm_idx = self._playback_modes.index(playlist.playback_mode)
        if pm_idx < pm_total - 1:
            pm_idx += 1
        else:
            pm_idx = 0
        playlist.playback_mode = self._playback_modes[pm_idx]

    def on_duration_changed(self, duration):
        m, s = parse_ms(duration)
        t = QTime(0, m, s)
        self.duration_label.setText(t.toString('mm:ss'))

    def on_position_changed(self, position):
        m, s = parse_ms(position)
        t = QTime(0, m, s)
        self.position_label.setText(t.toString('mm:ss'))

    def on_playback_mode_changed(self, playback_mode):
        self._update_pms_btn_text()

    def _update_pms_btn_text(self):
        playback_mode = self._app.player.playlist.playback_mode
        alias = self._pm_alias_map[playback_mode]
        self.pms_btn.setText(alias)

    def on_player_song_changed(self, song):
        self.song_title_label.setText('♪  {title} - {artists_name}'.format(
            title=song.title, artists_name=song.artists_name))

    def _on_player_state_changed(self, state):
        self.pp_btn.setChecked(state == State.playing)
コード例 #2
0
ファイル: ui.py プロジェクト: BruceZhang1993/FeelUOwn
class PlayerControlPanel(QFrame):

    def __init__(self, app, parent=None):
        super().__init__(parent)
        self._app = app

        class IconButton(QPushButton):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                # 按钮文字一般是一个 symbol,长度控制为 40 是满足需求的
                self.setMaximumWidth(40)

        self._playback_modes = list(PlaybackMode.__members__.values())
        self._pm_alias_map = {
            PlaybackMode.one_loop: '单曲循环',
            PlaybackMode.sequential: '顺序播放',
            PlaybackMode.loop: '循环播放',
            PlaybackMode.random: '随机播放',
        }

        # initialize sub widgets
        self._layout = QHBoxLayout(self)
        self.previous_btn = IconButton(self)
        self.pp_btn = IconButton(self)
        self.next_btn = IconButton(self)

        #: playback mode switch button
        self.pms_btn = QPushButton(self)
        self.volume_btn = VolumeButton(self)
        self.volume_btn.change_volume_needed.connect(
            lambda volume: setattr(self._app.player, 'volume', volume))
        self.playlist_btn = IconButton(parent=self)

        #: mark song as favorite button
        self.like_btn = QPushButton(self)
        self.mv_btn = QPushButton('MV', self)
        self.download_btn = QPushButton(self)

        self.previous_btn.setObjectName('previous_btn')
        self.pp_btn.setObjectName('pp_btn')
        self.next_btn.setObjectName('next_btn')
        self.playlist_btn.setObjectName('playlist_btn')
        self.volume_btn.setObjectName('volume_btn')
        self.pms_btn.setObjectName('pms_btn')
        self.download_btn.setObjectName('download_btn')
        self.like_btn.setObjectName('like_btn')
        self.mv_btn.setObjectName('mv_btn')

        self.progress_slider = ProgressSlider(self)

        self.pms_btn.setToolTip('修改播放模式')
        self.volume_btn.setToolTip('调整音量')
        self.playlist_btn.setToolTip('显示当前播放列表')
        self.progress_slider.setToolTip('拖动调节进度')

        # TODO: implementation
        self.mv_btn.setToolTip('播放 MV(未实现,欢迎 PR)')
        self.download_btn.setToolTip('下载歌曲(未实现,欢迎 PR)')
        self.like_btn.setToolTip('收藏歌曲(未实现,欢迎 PR)')

        if not use_mac_theme():
            self.previous_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipBackward))
            self.pp_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
            self.next_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipForward))
            self.volume_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume))
            self.playlist_btn.setText('🎶')
        else:
            self.pp_btn.setCheckable(True)
            self.like_btn.setCheckable(True)
            self.download_btn.setCheckable(True)

        self.song_title_label = QLabel('No song is playing.', parent=self)
        self.song_source_label = QLabel('歌曲来源', parent=self)
        self.song_title_label.setAlignment(Qt.AlignCenter)
        self.duration_label = QLabel('00:00', parent=self)
        self.position_label = QLabel('00:00', parent=self)

        self.song_source_label.setObjectName('song_source_label')

        self.next_btn.clicked.connect(self._app.player.play_next)
        self.previous_btn.clicked.connect(self._app.player.play_previous)
        self.pp_btn.clicked.connect(self._app.player.toggle)
        self.pms_btn.clicked.connect(self._switch_playback_mode)

        self._app.player.state_changed.connect(self._on_player_state_changed)
        self._app.player.playlist.playback_mode_changed.connect(
            self.on_playback_mode_changed)
        self._app.player.playlist.song_changed.connect(
            self.on_player_song_changed)
        self.progress_slider.resume_player_needed.connect(self._app.player.resume)
        self.progress_slider.pause_player_needed.connect(self._app.player.pause)
        self.progress_slider.change_position_needed.connect(
            lambda value: setattr(self._app.player, 'position', value))

        self._update_pms_btn_text()
        self._setup_ui()

    def _setup_ui(self):
        # set widget layout
        self.progress_slider.setMinimumWidth(480)
        self.progress_slider.setMaximumWidth(600)
        self.song_source_label.setFixedHeight(20)
        self.progress_slider.setFixedHeight(20)  # half of parent height
        self.position_label.setFixedWidth(45)
        self.duration_label.setFixedWidth(45)
        self.like_btn.setFixedSize(15, 15)
        self.download_btn.setFixedSize(15, 15)
        self.mv_btn.setFixedHeight(16)

        self.progress_slider.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self._sub_layout = QVBoxLayout()
        self._sub_top_layout = QHBoxLayout()

        # add space to make top layout align with progress slider
        self._sub_top_layout.addSpacing(3)
        self._sub_top_layout.addWidget(self.song_source_label)
        self._sub_top_layout.addSpacing(5)
        self._sub_top_layout.addWidget(self.song_title_label)
        self._sub_top_layout.addStretch(0)
        self._sub_top_layout.addWidget(self.like_btn)
        self._sub_top_layout.addSpacing(8)
        self._sub_top_layout.addWidget(self.mv_btn)
        self._sub_top_layout.addSpacing(8)
        self._sub_top_layout.addWidget(self.download_btn)
        self._sub_top_layout.addSpacing(3)

        self._sub_layout.addSpacing(3)
        self._sub_layout.addLayout(self._sub_top_layout)
        self._sub_layout.addWidget(self.progress_slider)

        self._layout.addSpacing(20)
        self._layout.addWidget(self.previous_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.pp_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.next_btn)
        self._layout.addSpacing(26)
        self._layout.addWidget(self.volume_btn)
        self._layout.addStretch(0)
        self._layout.addWidget(self.position_label)
        self._layout.addSpacing(7)
        self._layout.addLayout(self._sub_layout)
        self._layout.addSpacing(7)
        self._layout.addWidget(self.duration_label)
        self._layout.addSpacing(5)
        self._layout.addStretch(0)
        self._layout.addWidget(self.pms_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.playlist_btn)
        self._layout.addSpacing(18)

        self._layout.setSpacing(0)
        self._layout.setContentsMargins(0, 0, 0, 0)

    def _switch_playback_mode(self):
        playlist = self._app.player.playlist
        pm_total = len(self._playback_modes)
        pm_idx = self._playback_modes.index(playlist.playback_mode)
        if pm_idx < pm_total - 1:
            pm_idx += 1
        else:
            pm_idx = 0
        playlist.playback_mode = self._playback_modes[pm_idx]

    def on_duration_changed(self, duration):
        m, s = parse_ms(duration)
        t = QTime(0, m, s)
        self.duration_label.setText(t.toString('mm:ss'))

    def on_position_changed(self, position):
        m, s = parse_ms(position)
        t = QTime(0, m, s)
        self.position_label.setText(t.toString('mm:ss'))

    def on_playback_mode_changed(self, playback_mode):
        self._update_pms_btn_text()

    def _update_pms_btn_text(self):
        playback_mode = self._app.player.playlist.playback_mode
        alias = self._pm_alias_map[playback_mode]
        self.pms_btn.setText(alias)

    def on_player_song_changed(self, song):
        if song is None:
            self.song_source_label.setText('歌曲来源')
            self.song_title_label.setText('No song is playing.')
            return
        source_name_map = {p.identifier: p.name
                           for p in self._app.library.list()}
        font_metrics = QFontMetrics(QApplication.font())
        text = '{} - {}'.format(song.title, song.artists_name)
        elided_text = font_metrics.elidedText(
            text, Qt.ElideRight, self.progress_slider.width() - 100)
        self.song_source_label.setText(source_name_map[song.source])
        self.song_title_label.setText(elided_text)

    def _on_player_state_changed(self, state):
        self.pp_btn.setChecked(state == State.playing)
コード例 #3
0
ファイル: ui.py プロジェクト: zhangzhii/FeelUOwn
class PlayerControlPanel(QFrame):
    def __init__(self, app, parent=None):
        super().__init__(parent)
        self._app = app

        class IconButton(QPushButton):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                # 按钮文字一般是一个 symbol,长度控制为 40 是满足需求的
                self.setMaximumWidth(40)

        self._playback_modes = list(PlaybackMode.__members__.values())
        self._pm_alias_map = {
            PlaybackMode.one_loop: '单曲循环',
            PlaybackMode.sequential: '顺序播放',
            PlaybackMode.loop: '循环播放',
            PlaybackMode.random: '随机播放',
        }

        # initialize sub widgets
        self._layout = QHBoxLayout(self)
        self.previous_btn = IconButton(self)
        self.pp_btn = IconButton(self)
        self.next_btn = IconButton(self)

        #: playback mode switch button
        self.pms_btn = QPushButton(self)
        self.volume_btn = VolumeButton(self)
        self.volume_btn.change_volume_needed.connect(
            lambda volume: setattr(self._app.player, 'volume', volume))
        self.playlist_btn = IconButton(parent=self)

        #: mark song as favorite button
        self.like_btn = QPushButton(self)
        self.mv_btn = QPushButton('MV', self)
        self.download_btn = QPushButton(self)

        self.previous_btn.setObjectName('previous_btn')
        self.pp_btn.setObjectName('pp_btn')
        self.next_btn.setObjectName('next_btn')
        self.playlist_btn.setObjectName('playlist_btn')
        self.volume_btn.setObjectName('volume_btn')
        self.pms_btn.setObjectName('pms_btn')
        self.download_btn.setObjectName('download_btn')
        self.like_btn.setObjectName('like_btn')
        self.mv_btn.setObjectName('mv_btn')

        self.progress_slider = ProgressSlider(self)

        self.pms_btn.setToolTip('修改播放模式')
        self.volume_btn.setToolTip('调整音量')
        self.playlist_btn.setToolTip('显示当前播放列表')
        self.progress_slider.setToolTip('拖动调节进度')

        # TODO: implementation
        self.mv_btn.setToolTip('播放 MV(未实现,欢迎 PR)')
        self.download_btn.setToolTip('下载歌曲(未实现,欢迎 PR)')
        self.like_btn.setToolTip('收藏歌曲(未实现,欢迎 PR)')

        if not use_mac_theme():
            self.previous_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaSkipBackward))
            self.pp_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
            self.next_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaSkipForward))
            self.volume_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaVolume))
            self.playlist_btn.setText('🎶')
        else:
            self.pp_btn.setCheckable(True)
            self.like_btn.setCheckable(True)
            self.download_btn.setCheckable(True)

        self.song_title_label = QLabel('No song is playing.', parent=self)
        self.song_source_label = QLabel('歌曲来源', parent=self)
        self.song_title_label.setAlignment(Qt.AlignCenter)
        self.duration_label = QLabel('00:00', parent=self)
        self.position_label = QLabel('00:00', parent=self)

        self.song_source_label.setObjectName('song_source_label')

        self.next_btn.clicked.connect(self._app.player.play_next)
        self.previous_btn.clicked.connect(self._app.player.play_previous)
        self.pp_btn.clicked.connect(self._app.player.toggle)
        self.pms_btn.clicked.connect(self._switch_playback_mode)

        self._app.player.state_changed.connect(self._on_player_state_changed)
        self._app.player.playlist.playback_mode_changed.connect(
            self.on_playback_mode_changed)
        self._app.player.playlist.song_changed.connect(
            self.on_player_song_changed)
        self.progress_slider.resume_player_needed.connect(
            self._app.player.resume)
        self.progress_slider.pause_player_needed.connect(
            self._app.player.pause)
        self.progress_slider.change_position_needed.connect(
            lambda value: setattr(self._app.player, 'position', value))

        self._update_pms_btn_text()
        self._setup_ui()

    def _setup_ui(self):
        # set widget layout
        self.progress_slider.setMinimumWidth(480)
        self.progress_slider.setMaximumWidth(600)
        self.song_source_label.setFixedHeight(20)
        self.progress_slider.setFixedHeight(20)  # half of parent height
        self.position_label.setFixedWidth(45)
        self.duration_label.setFixedWidth(45)
        self.like_btn.setFixedSize(15, 15)
        self.download_btn.setFixedSize(15, 15)
        self.mv_btn.setFixedHeight(16)

        self.progress_slider.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Preferred)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self._sub_layout = QVBoxLayout()
        self._sub_top_layout = QHBoxLayout()

        # add space to make top layout align with progress slider
        self._sub_top_layout.addSpacing(3)
        self._sub_top_layout.addWidget(self.song_source_label)
        self._sub_top_layout.addSpacing(5)
        self._sub_top_layout.addWidget(self.song_title_label)
        self._sub_top_layout.addStretch(0)
        self._sub_top_layout.addWidget(self.like_btn)
        self._sub_top_layout.addSpacing(8)
        self._sub_top_layout.addWidget(self.mv_btn)
        self._sub_top_layout.addSpacing(8)
        self._sub_top_layout.addWidget(self.download_btn)
        self._sub_top_layout.addSpacing(3)

        self._sub_layout.addSpacing(3)
        self._sub_layout.addLayout(self._sub_top_layout)
        self._sub_layout.addWidget(self.progress_slider)

        self._layout.addSpacing(20)
        self._layout.addWidget(self.previous_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.pp_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.next_btn)
        self._layout.addSpacing(26)
        self._layout.addWidget(self.volume_btn)
        self._layout.addStretch(0)
        self._layout.addWidget(self.position_label)
        self._layout.addSpacing(7)
        self._layout.addLayout(self._sub_layout)
        self._layout.addSpacing(7)
        self._layout.addWidget(self.duration_label)
        self._layout.addSpacing(5)
        self._layout.addStretch(0)
        self._layout.addWidget(self.pms_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.playlist_btn)
        self._layout.addSpacing(18)

        self._layout.setSpacing(0)
        self._layout.setContentsMargins(0, 0, 0, 0)

    def _switch_playback_mode(self):
        playlist = self._app.player.playlist
        pm_total = len(self._playback_modes)
        pm_idx = self._playback_modes.index(playlist.playback_mode)
        if pm_idx < pm_total - 1:
            pm_idx += 1
        else:
            pm_idx = 0
        playlist.playback_mode = self._playback_modes[pm_idx]

    def on_duration_changed(self, duration):
        m, s = parse_ms(duration)
        t = QTime(0, m, s)
        self.duration_label.setText(t.toString('mm:ss'))

    def on_position_changed(self, position):
        m, s = parse_ms(position)
        t = QTime(0, m, s)
        self.position_label.setText(t.toString('mm:ss'))

    def on_playback_mode_changed(self, playback_mode):
        self._update_pms_btn_text()

    def _update_pms_btn_text(self):
        playback_mode = self._app.player.playlist.playback_mode
        alias = self._pm_alias_map[playback_mode]
        self.pms_btn.setText(alias)

    def on_player_song_changed(self, song):
        if song is None:
            self.song_source_label.setText('歌曲来源')
            self.song_title_label.setText('No song is playing.')
            return
        source_name_map = {
            p.identifier: p.name
            for p in self._app.library.list()
        }
        font_metrics = QFontMetrics(QApplication.font())
        text = '{} - {}'.format(song.title, song.artists_name)
        elided_text = font_metrics.elidedText(
            text, Qt.ElideRight,
            self.progress_slider.width() - 100)
        self.song_source_label.setText(source_name_map[song.source])
        self.song_title_label.setText(elided_text)

    def _on_player_state_changed(self, state):
        self.pp_btn.setChecked(state == State.playing)
コード例 #4
0
ファイル: ui.py プロジェクト: liangdaojun/FeelUOwn
class PlayerControlPanel(QFrame):
    def __init__(self, app, parent=None):
        super().__init__(parent)
        self._app = app

        class Button(QPushButton):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                # 按钮文字一般是一个 symbol,长度控制为 40 是满足需求的
                self.setMaximumWidth(40)

        # initialize sub widgets
        self._layout = QHBoxLayout(self)
        self.previous_btn = Button(self)
        self.pp_btn = Button(self)
        self.next_btn = Button(self)
        self.pms_btn = Button(self)
        self.volume_btn = VolumeButton(self)
        self.volume_btn.change_volume_needed.connect(
            lambda volume: setattr(self._app.player, 'volume', volume))
        self.playlist_btn = Button(parent=self)

        self.previous_btn.setObjectName('previous_btn')
        self.pp_btn.setObjectName('pp_btn')
        self.next_btn.setObjectName('next_btn')
        self.playlist_btn.setObjectName('playlist_btn')
        self.volume_btn.setObjectName('volume_btn')

        self.progress_slider = ProgressSlider(self)

        # TODO(simple): implementation
        self.pms_btn.setToolTip('修改播放模式(未实现,欢迎 PR)')
        self.volume_btn.setToolTip('调整音量(未实现,欢迎 PR)')
        self.playlist_btn.setToolTip('显示当前播放列表')
        self.progress_slider.setToolTip('拖动调节进度(未实现,欢迎 PR)')

        if not use_mac_theme():
            self.previous_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaSkipBackward))
            self.pp_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
            self.next_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaSkipForward))
            self.volume_btn.setIcon(self.style().standardIcon(
                QStyle.SP_MediaVolume))
            self.playlist_btn.setText('🎶')
        else:
            self.pp_btn.setCheckable(True)

        self.song_title_label = QLabel('No song is playing.', parent=self)
        self.song_title_label.setAlignment(Qt.AlignCenter)
        self.duration_label = QLabel('00:00', parent=self)
        self.position_label = QLabel('00:00', parent=self)

        self.next_btn.clicked.connect(self._app.player.play_next)
        self.previous_btn.clicked.connect(self._app.player.play_previous)
        self.pp_btn.clicked.connect(self._app.player.toggle)

        # set widget layout
        self.progress_slider.setMinimumWidth(480)
        self.progress_slider.setMaximumWidth(600)
        self.progress_slider.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Preferred)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self._sub_layout = QVBoxLayout()
        self._sub_layout.addWidget(self.song_title_label)
        self._sub_layout.addWidget(self.progress_slider)

        self._layout.addSpacing(20)
        self._layout.addWidget(self.previous_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.pp_btn)
        self._layout.addSpacing(8)
        self._layout.addWidget(self.next_btn)
        self._layout.addSpacing(26)
        self._layout.addWidget(self.volume_btn)
        self._layout.addStretch(0)
        self._layout.addWidget(self.position_label)
        self._layout.addSpacing(7)
        self._layout.addLayout(self._sub_layout)
        self._layout.addSpacing(7)
        self._layout.addWidget(self.duration_label)
        self._layout.addSpacing(5)
        self._layout.addStretch(0)
        self._layout.addWidget(self.pms_btn)
        self._layout.addWidget(self.playlist_btn)
        self._layout.addSpacing(18)

        self._layout.setSpacing(0)
        self._layout.setContentsMargins(0, 0, 0, 0)

    def on_duration_changed(self, duration):
        m, s = parse_ms(duration)
        t = QTime(0, m, s)
        self.duration_label.setText(t.toString('mm:ss'))

    def on_position_changed(self, position):
        m, s = parse_ms(position)
        t = QTime(0, m, s)
        self.position_label.setText(t.toString('mm:ss'))

    def on_playback_mode_changed(self, playback_mode):
        self.pms_btn.setText(playback_mode.value)

    def on_player_song_changed(self, song):
        self.song_title_label.setText('♪  {title} - {artists_name}'.format(
            title=song.title, artists_name=song.artists_name))