コード例 #1
0
class Example_Window(QWidgets.QWidget):
    def __init__(self):
        super(QWidgets.QWidget, self).__init__()

        self.initUI()

    def initUI(self):
        self.button = QWidgets.QPushButton("Start Spinner")  # +
        self.button.clicked.connect(self.toggle_spinner)

        self.spinner = QtWaitingSpinner(self, centerOnParent=False)

        self.grid = QWidgets.QGridLayout()
        self.grid.addWidget(self.button, 0, 0)

        #        self.grid.addWidget(self.spinner,0,1)        # ---
        self.grid.addWidget(self.spinner, 0, 1, 1, 2)  # +++    <---

        self.setLayout(self.grid)
        self.show()

    def toggle_spinner(self):
        if self.spinner.isSpinning():
            self.spinner.stop()
            self.button.setText("Start Spinner")  # +
        else:
            self.spinner.start()
            self.button.setText("Stop Spinner")  # +
コード例 #2
0
class Dialog(QDialog):
    def __init__(self, *args, **kwargs):
        QDialog.__init__(self, *args, **kwargs)
        self.setLayout(QVBoxLayout())
        btn = QPushButton("Submit", self)
        btn.clicked.connect(self.submit)
        self.spinner = QtWaitingSpinner(self)

        self.layout().addWidget(btn)
        self.layout().addWidget(self.spinner)

    def submit(self):
        self.spinner.start()
        runnable = RequestRunnable("https://api.github.com/some/endpoint",
                                   {'some': 'data'}, self)
        QThreadPool.globalInstance().start(runnable)

    @pyqtSlot(str)
    def setData(self, data):
        print(data)
        self.spinner.stop()
        self.adjustSize()
コード例 #3
0
class Demo(QWidget):
    sb_roundness = None
    sb_opacity = None
    sb_fadeperc = None
    sb_lines = None
    sb_line_length = None
    sb_line_width = None
    sb_inner_radius = None
    sb_rev_s = None

    btn_start = None
    btn_stop = None
    btn_pick_color = None

    spinner = None

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

    def init_ui(self):
        grid = QGridLayout()
        groupbox1 = QGroupBox()
        groupbox1_layout = QHBoxLayout()
        groupbox2 = QGroupBox()
        groupbox2_layout = QGridLayout()
        button_hbox = QHBoxLayout()
        self.setLayout(grid)
        self.setWindowTitle("QtWaitingSpinner Demo")
        self.setWindowFlags(Qt.Dialog)

        # SPINNER
        self.spinner = QtWaitingSpinner(self)

        # Spinboxes
        self.sb_roundness = QDoubleSpinBox()
        self.sb_opacity = QDoubleSpinBox()
        self.sb_fadeperc = QDoubleSpinBox()
        self.sb_lines = QSpinBox()
        self.sb_line_length = QDoubleSpinBox()
        self.sb_line_width = QDoubleSpinBox()
        self.sb_inner_radius = QDoubleSpinBox()
        self.sb_rev_s = QDoubleSpinBox()

        # set spinbox default values
        self.sb_roundness.setValue(70)
        self.sb_roundness.setRange(0, 9999)
        self.sb_opacity.setValue(15)
        self.sb_opacity.setRange(0, 9999)
        self.sb_fadeperc.setValue(70)
        self.sb_fadeperc.setRange(0, 9999)
        self.sb_lines.setValue(12)
        self.sb_lines.setRange(1, 9999)
        self.sb_line_length.setValue(10)
        self.sb_line_length.setRange(0, 9999)
        self.sb_line_width.setValue(5)
        self.sb_line_width.setRange(0, 9999)
        self.sb_inner_radius.setValue(10)
        self.sb_inner_radius.setRange(0, 9999)
        self.sb_rev_s.setValue(1)
        self.sb_rev_s.setRange(0.1, 9999)

        # Buttons
        self.btn_start = QPushButton("Start")
        self.btn_stop = QPushButton("Stop")
        self.btn_pick_color = QPushButton("Pick Color")

        # Connects
        self.sb_roundness.valueChanged.connect(self.set_roundness)
        self.sb_opacity.valueChanged.connect(self.set_opacity)
        self.sb_fadeperc.valueChanged.connect(self.set_fadeperc)
        self.sb_lines.valueChanged.connect(self.set_lines)
        self.sb_line_length.valueChanged.connect(self.set_line_length)
        self.sb_line_width.valueChanged.connect(self.set_line_width)
        self.sb_inner_radius.valueChanged.connect(self.set_inner_radius)
        self.sb_rev_s.valueChanged.connect(self.set_rev_s)

        self.btn_start.clicked.connect(self.spinner_start)
        self.btn_stop.clicked.connect(self.spinner_stop)
        self.btn_pick_color.clicked.connect(self.show_color_picker)

        # Layout adds
        groupbox1_layout.addWidget(self.spinner)
        groupbox1.setLayout(groupbox1_layout)

        groupbox2_layout.addWidget(QLabel("Roundness:"), *(1, 1))
        groupbox2_layout.addWidget(self.sb_roundness, *(1, 2))
        groupbox2_layout.addWidget(QLabel("Opacity:"), *(2, 1))
        groupbox2_layout.addWidget(self.sb_opacity, *(2, 2))
        groupbox2_layout.addWidget(QLabel("Fade Perc:"), *(3, 1))
        groupbox2_layout.addWidget(self.sb_fadeperc, *(3, 2))
        groupbox2_layout.addWidget(QLabel("Lines:"), *(4, 1))
        groupbox2_layout.addWidget(self.sb_lines, *(4, 2))
        groupbox2_layout.addWidget(QLabel("Line Length:"), *(5, 1))
        groupbox2_layout.addWidget(self.sb_line_length, *(5, 2))
        groupbox2_layout.addWidget(QLabel("Line Width:"), *(6, 1))
        groupbox2_layout.addWidget(self.sb_line_width, *(6, 2))
        groupbox2_layout.addWidget(QLabel("Inner Radius:"), *(7, 1))
        groupbox2_layout.addWidget(self.sb_inner_radius, *(7, 2))
        groupbox2_layout.addWidget(QLabel("Rev/s:"), *(8, 1))
        groupbox2_layout.addWidget(self.sb_rev_s, *(8, 2))

        groupbox2.setLayout(groupbox2_layout)

        button_hbox.addWidget(self.btn_start)
        button_hbox.addWidget(self.btn_stop)
        button_hbox.addWidget(self.btn_pick_color)

        grid.addWidget(groupbox1, *(1, 1))
        grid.addWidget(groupbox2, *(1, 2))
        grid.addLayout(button_hbox, *(2, 1))

        self.spinner.start()
        self.show()

    def set_roundness(self):
        self.spinner.setRoundness(self.sb_roundness.value())

    def set_opacity(self):
        self.spinner.setMinimumTrailOpacity(self.sb_opacity.value())

    def set_fadeperc(self):
        self.spinner.setTrailFadePercentage(self.sb_fadeperc.value())

    def set_lines(self):
        self.spinner.setNumberOfLines(self.sb_lines.value())

    def set_line_length(self):
        self.spinner.setLineLength(self.sb_line_length.value())

    def set_line_width(self):
        self.spinner.setLineWidth(self.sb_line_width.value())

    def set_inner_radius(self):
        self.spinner.setInnerRadius(self.sb_inner_radius.value())

    def set_rev_s(self):
        self.spinner.setRevolutionsPerSecond(self.sb_rev_s.value())

    def spinner_start(self):
        self.spinner.start()

    def spinner_stop(self):
        self.spinner.stop()

    def show_color_picker(self):
        self.spinner.setColor(QColorDialog.getColor())
コード例 #4
0
ファイル: demo.py プロジェクト: z3ntu/QtWaitingSpinner
class Demo(QWidget):
    sb_roundness = None
    sb_opacity = None
    sb_fadeperc = None
    sb_lines = None
    sb_line_length = None
    sb_line_width = None
    sb_inner_radius = None
    sb_rev_s = None

    btn_start = None
    btn_stop = None
    btn_pick_color = None

    spinner = None

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

    def init_ui(self):
        grid = QGridLayout()
        groupbox1 = QGroupBox()
        groupbox1_layout = QHBoxLayout()
        groupbox2 = QGroupBox()
        groupbox2_layout = QGridLayout()
        button_hbox = QHBoxLayout()
        self.setLayout(grid)
        self.setWindowTitle("QtWaitingSpinner Demo")
        self.setWindowFlags(Qt.Dialog)

        # SPINNER
        self.spinner = QtWaitingSpinner(self)

        # Spinboxes
        self.sb_roundness = QDoubleSpinBox()
        self.sb_opacity = QDoubleSpinBox()
        self.sb_fadeperc = QDoubleSpinBox()
        self.sb_lines = QSpinBox()
        self.sb_line_length = QDoubleSpinBox()
        self.sb_line_width = QDoubleSpinBox()
        self.sb_inner_radius = QDoubleSpinBox()
        self.sb_rev_s = QDoubleSpinBox()

        # set spinbox default values
        self.sb_roundness.setValue(70)
        self.sb_roundness.setRange(0, 9999)
        self.sb_opacity.setValue(15)
        self.sb_opacity.setRange(0, 9999)
        self.sb_fadeperc.setValue(70)
        self.sb_fadeperc.setRange(0, 9999)
        self.sb_lines.setValue(12)
        self.sb_lines.setRange(1, 9999)
        self.sb_line_length.setValue(10)
        self.sb_line_length.setRange(0, 9999)
        self.sb_line_width.setValue(5)
        self.sb_line_width.setRange(0, 9999)
        self.sb_inner_radius.setValue(10)
        self.sb_inner_radius.setRange(0, 9999)
        self.sb_rev_s.setValue(1)
        self.sb_rev_s.setRange(0.1, 9999)

        # Buttons
        self.btn_start = QPushButton("Start")
        self.btn_stop = QPushButton("Stop")
        self.btn_pick_color = QPushButton("Pick Color")

        # Connects
        self.sb_roundness.valueChanged.connect(self.set_roundness)
        self.sb_opacity.valueChanged.connect(self.set_opacity)
        self.sb_fadeperc.valueChanged.connect(self.set_fadeperc)
        self.sb_lines.valueChanged.connect(self.set_lines)
        self.sb_line_length.valueChanged.connect(self.set_line_length)
        self.sb_line_width.valueChanged.connect(self.set_line_width)
        self.sb_inner_radius.valueChanged.connect(self.set_inner_radius)
        self.sb_rev_s.valueChanged.connect(self.set_rev_s)

        self.btn_start.clicked.connect(self.spinner_start)
        self.btn_stop.clicked.connect(self.spinner_stop)
        self.btn_pick_color.clicked.connect(self.show_color_picker)

        # Layout adds
        groupbox1_layout.addWidget(self.spinner)
        groupbox1.setLayout(groupbox1_layout)

        groupbox2_layout.addWidget(QLabel("Roundness:"), *(1, 1))
        groupbox2_layout.addWidget(self.sb_roundness, *(1, 2))
        groupbox2_layout.addWidget(QLabel("Opacity:"), *(2, 1))
        groupbox2_layout.addWidget(self.sb_opacity, *(2, 2))
        groupbox2_layout.addWidget(QLabel("Fade Perc:"), *(3, 1))
        groupbox2_layout.addWidget(self.sb_fadeperc, *(3, 2))
        groupbox2_layout.addWidget(QLabel("Lines:"), *(4, 1))
        groupbox2_layout.addWidget(self.sb_lines, *(4, 2))
        groupbox2_layout.addWidget(QLabel("Line Length:"), *(5, 1))
        groupbox2_layout.addWidget(self.sb_line_length, *(5, 2))
        groupbox2_layout.addWidget(QLabel("Line Width:"), *(6, 1))
        groupbox2_layout.addWidget(self.sb_line_width, *(6, 2))
        groupbox2_layout.addWidget(QLabel("Inner Radius:"), *(7, 1))
        groupbox2_layout.addWidget(self.sb_inner_radius, *(7, 2))
        groupbox2_layout.addWidget(QLabel("Rev/s:"), *(8, 1))
        groupbox2_layout.addWidget(self.sb_rev_s, *(8, 2))

        groupbox2.setLayout(groupbox2_layout)

        button_hbox.addWidget(self.btn_start)
        button_hbox.addWidget(self.btn_stop)
        button_hbox.addWidget(self.btn_pick_color)

        grid.addWidget(groupbox1, *(1, 1))
        grid.addWidget(groupbox2, *(1, 2))
        grid.addLayout(button_hbox, *(2, 1))

        self.spinner.start()
        self.show()

    def set_roundness(self):
        self.spinner.setRoundness(self.sb_roundness.value())

    def set_opacity(self):
        self.spinner.setMinimumTrailOpacity(self.sb_opacity.value())

    def set_fadeperc(self):
        self.spinner.setTrailFadePercentage(self.sb_fadeperc.value())

    def set_lines(self):
        self.spinner.setNumberOfLines(self.sb_lines.value())

    def set_line_length(self):
        self.spinner.setLineLength(self.sb_line_length.value())

    def set_line_width(self):
        self.spinner.setLineWidth(self.sb_line_width.value())

    def set_inner_radius(self):
        self.spinner.setInnerRadius(self.sb_inner_radius.value())

    def set_rev_s(self):
        self.spinner.setRevolutionsPerSecond(self.sb_rev_s.value())

    def spinner_start(self):
        self.spinner.start()

    def spinner_stop(self):
        self.spinner.stop()

    def show_color_picker(self):
        self.spinner.setColor(QColorDialog.getColor())
コード例 #5
0
class Window(QWidget):

    sig_abort_workers = pyqtSignal()

    def __init__(self, val, screenwidth, screenheight, parent=None):
        super().__init__(parent)
        self.setWindowTitle("qtube")

        app_exit_shortcuts = ["Ctrl+Q", "Ctrl+W"]
        for sc in app_exit_shortcuts:
            exitshortcut = QShortcut(QKeySequence(sc), self)
            exitshortcut.activated.connect(self.exit_seq)

        backshortcut = QShortcut(QKeySequence('Alt+Left'), self)
        backshortcut.activated.connect(self.on_back_clicked)

        self.setStyleSheet("background-color: " + BACKGROUND_COLOR + ";")

        self.mygroupbox = QGroupBox('')
        self.mygroupbox.setStyleSheet("color: " + FOREGROUND_COLOR +
                                      "; font-family: " + FONT +
                                      "; font-style: italic")
        self.myform = QFormLayout()
        labellist = []
        combolist = []

        self.mygroupbox.setLayout(self.myform)
        self.scroll = QScrollArea()
        self.scroll.setWidget(self.mygroupbox)
        self.scroll.setWidgetResizable(True)
        self.scroll.setStyleSheet("color: " + FOREGROUND_COLOR + ";")

        self.history = {
            'urls': [],
            'title_boxes': [],
            'data': [],
            'page_numbers': []
        }
        self.downloaded_videos = {'paths': [], 'short_titles': []}
        self.search = ''

        self.spinner = QtWaitingSpinner(self, False)
        self.spinner.setRoundness(70.0)
        self.spinner.setMinimumTrailOpacity(15.0)
        self.spinner.setTrailFadePercentage(70.0)
        self.spinner.setNumberOfLines(10)
        self.spinner.setLineLength(10)
        self.spinner.setLineWidth(4)
        self.spinner.setInnerRadius(4)
        self.spinner.setRevolutionsPerSecond(1.5)
        self.spinner.setColor(QColor(FOREGROUND_COLOR))

        # multi-threading
        QThread.currentThread().setObjectName(
            'main')  # threads can be named, useful for log output
        self.__workers_done = []
        self.__threads = []

        self.line = QLineEdit(self)
        self.line.returnPressed.connect(self.clickMethod)
        self.line.setStyleSheet("color: " + FOREGROUND_COLOR +
                                "; background-color: " + BACKGROUND_COLOR +
                                "; border: 1px solid " + FOREGROUND_COLOR +
                                "; font-family: " + FONT + ";")

        active_buttons = []
        self.inactive_buttons = []

        self.search_button = QPushButton()
        self.search_button.setText('Search')
        self.search_button.clicked.connect(self.clickMethod)
        active_buttons.append(self.search_button)

        self.home_button = QPushButton()
        self.home_button.setText('Home')
        self.home_button.clicked.connect(self.on_home_clicked)
        self.inactive_buttons.append(self.home_button)

        self.play_playlist_button = QPushButton()
        self.play_playlist_button.setText('Play All')
        self.play_playlist_button.clicked.connect(
            self.on_play_playlist_clicked)
        active_buttons.append(self.play_playlist_button)

        self.back_button = QPushButton()
        self.back_button.setText('Back')
        self.back_button.clicked.connect(self.on_back_clicked)
        self.inactive_buttons.append(self.back_button)

        for b in active_buttons:
            b.setStyleSheet("color: " + FOREGROUND_COLOR +
                            "; background-color: " + BACKGROUND_COLOR +
                            "; border: 1px solid " + FOREGROUND_COLOR +
                            "; font-family: " + FONT + ";")
            b.setCursor(Qt.PointingHandCursor)

        for b in self.inactive_buttons:
            b.setStyleSheet("color: " + INACTIVE_COLOR +
                            "; background-color: " + BACKGROUND_COLOR +
                            "; border: 1px solid " + INACTIVE_COLOR +
                            "; font-family: " + FONT + ";")

        self.download_label = QLabel()
        self.download_label.setText('0 downloads')
        self.download_label.setMaximumSize(QSize(110, 20))
        self.download_label.setStyleSheet("color: " + INACTIVE_COLOR +
                                          "; background-color: " +
                                          BACKGROUND_COLOR +
                                          "; font-family: " + FONT + ";")

        self.download_selector = QComboBox()
        self.download_selector.setStyleSheet("color: " + INACTIVE_COLOR +
                                             "; background-color: " +
                                             BACKGROUND_COLOR +
                                             "; font-family: " + FONT + ";")
        self.download_selector.currentIndexChanged.connect(
            self.select_download)

        self.download_to_play = ''

        self.play_downloaded_button = QPushButton()
        self.play_downloaded_button.setText('Play')
        self.play_downloaded_button.clicked.connect(self.on_play_downloaded)
        self.play_downloaded_button.setMaximumSize(QSize(50, 20))
        self.play_downloaded_button.setStyleSheet("color: " + INACTIVE_COLOR +
                                                  "; background-color: " +
                                                  BACKGROUND_COLOR +
                                                  "; border: 1px solid " +
                                                  INACTIVE_COLOR +
                                                  "; font-family: " + FONT +
                                                  ";")

        self.container = VideoContainer(PLAYER_SIZE)
        self.container.setAttribute(Qt.WA_DontCreateNativeAncestors)
        self.container.setAttribute(Qt.WA_NativeWindow)
        #self.container.sig_height.connect(self.resizeWindow)

        self.player = mpv.MPV(
            wid=str(int(self.container.winId())),
            ytdl=True,
            input_default_bindings=True,
            input_vo_keyboard=True,
            keep_open=True,
            reset_on_next_file='pause',
            osd_bar=True,
        )

        script_dir = str(Path.home()) + '/.config/mpv/scripts/'
        [
            self.player.command('load-script', script_dir + script)
            for script in os.listdir(script_dir)
        ]

        player_exit_shortcuts = ['q', 'ctrl+q', 'ctrl+w']
        for sc in player_exit_shortcuts:
            self.player.register_key_binding(sc, self.exit_seq)

        self.player.register_key_binding('f', self.fullscreen)
        self.player.register_key_binding('esc', self.fullscreen_off)
        self.isFullScreen = False

        self.player.register_key_binding('WHEEL_LEFT', 'seek 1')
        self.player.register_key_binding('WHEEL_RIGHT', 'seek -1')

        searchbarlayout = QHBoxLayout()
        searchbarlayout.addWidget(self.line)
        searchbarlayout.addWidget(self.search_button)
        searchbarlayout.addWidget(self.spinner)
        searchbar = QWidget()
        searchbar.setLayout(searchbarlayout)

        buttonrowlayout = QHBoxLayout()
        buttonrowlayout.addWidget(self.back_button)
        buttonrowlayout.addWidget(self.home_button)
        buttonrowlayout.addWidget(self.play_playlist_button)
        buttonrow = QWidget()
        buttonrow.setLayout(buttonrowlayout)

        downloadrowlayout = QHBoxLayout()
        downloadrowlayout.addWidget(self.download_label)
        downloadrowlayout.addWidget(self.download_selector)
        downloadrowlayout.addWidget(self.play_downloaded_button)
        downloadrow = QWidget()
        downloadrow.setLayout(downloadrowlayout)

        sublayout = QVBoxLayout()
        sublayout.addWidget(searchbar)
        sublayout.addWidget(buttonrow)
        sublayout.addWidget(self.scroll)
        sublayout.addWidget(downloadrow)
        self.left = QWidget()
        self.left.setLayout(sublayout)
        self.left.setFixedWidth(LIST_WIDTH)

        biglayout = QHBoxLayout(self)
        biglayout.addWidget(self.left)
        biglayout.addWidget(self.container)
        biglayout.setContentsMargins(0, 0, 0, 0)

        self.move(int((screenwidth - PLAYER_SIZE.width() - LIST_WIDTH) / 2),
                  int((screenheight - PLAYER_SIZE.height()) / 2))

        # load home page data
        self.spinner.start()

        idx = 'Home'
        worker = Worker(idx, HOME_URL, search=False)
        thread = QThread()
        thread.setObjectName('thread_' + idx)
        worker.moveToThread(thread)

        worker.sig_data.connect(self.on_click_data_received)

        self.sig_abort_workers.connect(worker.abort)

        thread.started.connect(worker.grabData)
        thread.start()
        self.__threads.append((thread, worker))

    def fullscreen(self, blank, blank2):
        if not self.isFullScreen:
            self.left.setFixedWidth(0)
            self.showFullScreen()
            self.isFullScreen = True
            time.sleep(.5)

    def fullscreen_off(self, blank, blank2):
        if self.isFullScreen:
            self.showNormal()
            self.left.setFixedWidth(LIST_WIDTH)
            self.isFullScreen = False
            time.sleep(.5)

    # @pyqtSlot(int)
    # def resizeWindow(self, newheight):
    #     self.setFixedHeight(newheight)

    def clickMethod(self):

        self.spinner.start()

        self.search = self.line.text()
        print('searching "' + self.search + '"...')

        idx = 'clickMethod'
        worker = Worker(idx, self.search)
        thread = QThread()
        thread.setObjectName('thread_' + idx)
        self.__threads.append((thread, worker))
        worker.moveToThread(thread)

        worker.sig_data.connect(self.on_click_data_received)

        self.sig_abort_workers.connect(worker.abort)

        thread.started.connect(worker.grabData)
        thread.start()

    @pyqtSlot(dict)
    def on_click_data_received(self, data):

        self.data = sort_dict_lists_by_list(data, 'titles')

        search_term = self.search

        if len(self.history['data']) == 0:
            title_box = data['page_title']
        elif len(search_term) > 25:
            title_box = 'results: "' + search_term[:22] + '..."'
        else:
            title_box = 'results: "' + search_term + '"'

        if len(self.history['data']) > 0:
            for b in self.inactive_buttons:
                b.setStyleSheet("color: " + FOREGROUND_COLOR +
                                "; background-color: " + BACKGROUND_COLOR +
                                "; border: 1px solid " + FOREGROUND_COLOR +
                                "; font-family: " + FONT + ";")
                b.setCursor(Qt.PointingHandCursor)

        self.history['data'].append(self.data)
        self.history['title_boxes'].append(title_box)
        self.history['urls'].append(self.data['playlist_url'])
        self.history['page_numbers'].append(1)

        self.populate()
        groupbox = QGroupBox(title_box)
        groupbox.setLayout(self.myform)
        groupbox.setStyleSheet("color: " + FOREGROUND_COLOR +
                               "; font-family: " + FONT +
                               ";font-style: italic")
        self.scroll.setWidget(groupbox)
        self.spinner.stop()

    def populate(self):

        labellist = []
        combolist = []
        form = QFormLayout()

        for i, img in enumerate(self.data['thumb_paths']):

            if self.data['titles'][i] is not None:
                title = '\n'.join(
                    textwrap.wrap(self.data['titles'][i], TEXT_LENGTH)[:2])
                if len(self.data['titles'][i]) > TEXT_LENGTH * 2:
                    title = title + '...'
            else:  # catch errors from youtube-dl failing to capture video title
                title = '[TITLE MISSING]'

            text = title + '\n' + self.data['durations'][
                i] + ' | ' + self.data['dates'][i] + '\n' + self.data['views'][
                    i] + ' views | ' + self.data['ratings'][i] + ' likes'

            descLabel = DescriptionLabel(self.data['urls'][i],
                                         self.data['titles'][i])
            descLabel.setText(text)
            descLabel.setMaximumWidth(TEXT_WIDTH)
            descLabel.video_clicked.connect(self.on_video_clicked)
            descLabel.download_clicked.connect(self.on_download_clicked)
            labellist.append(descLabel)

            imagelabel = ImageLabel(self.data['urls'][i],
                                    self.data['titles'][i])
            pixmap = QPixmap(img)
            pixmap = pixmap.scaled(THUMB_SIZE, FLAGS)
            imagelabel.setPixmap(pixmap)
            imagelabel.video_clicked.connect(self.on_video_clicked)
            imagelabel.download_clicked.connect(self.on_download_clicked)
            combolist.append(imagelabel)  #
            form.addRow(combolist[i], labellist[i])

        number_of_pages = math.ceil(self.data['total_videos'] / NUM_RESULTS)

        if number_of_pages > 1:

            current_page = self.history['page_numbers'][-1]
            pages = []

            if current_page <= 3 or number_of_pages <= 5:
                page_range = ['<']
                page_range.extend([i for i in range(1, number_of_pages + 1)])
                page_range.append('>')

            else:
                page_range = ['<', 1]
                if number_of_pages - current_page < 3:
                    page_range.extend([
                        i for i in range(number_of_pages - 3, number_of_pages +
                                         1)
                    ])
                else:
                    page_range.extend([i + current_page - 1 for i in range(4)])
                page_range.append('>')

            for i in page_range:
                active = (i != current_page
                          ) and not (i == '<' and current_page == 1) and not (
                              i == '>' and current_page == number_of_pages)
                page = PageLabel(i, active)
                page.page_clicked.connect(self.get_next_page)
                pages.append(page)

            layout = QHBoxLayout()
            for p in pages:
                layout.addWidget(p)
            page_selector = QWidget()
            page_selector.setLayout(layout)
            form.addRow(QLabel('Pages: '), page_selector)

        self.myform = form

    def exit_seq(self, blank=None, blank2=None):
        app.quit()

    def on_video_clicked(self):

        label = self.sender()
        self.url = label.url
        self.player.play(self.url)
        #self.player.command('show-text', label.title)

    def on_download_clicked(self):

        label = self.sender()

        idx = label.title
        worker = Worker(idx, label.url, label=self.download_label)
        thread = QThread()
        thread.setObjectName('thread_' + idx)
        self.__threads.append(
            (thread,
             worker))  # need to store worker too otherwise will be gc'd
        worker.moveToThread(thread)

        worker.sig_msg.connect(self.on_download_complete)

        self.sig_abort_workers.connect(worker.abort)

        # get read to start worker:
        thread.started.connect(worker.download)
        thread.start(
        )  # this will emit 'started' and start thread's event loop

    @pyqtSlot(str)
    def on_download_complete(self, title):

        title_short = title[:20]

        vid_path = [
            DOWNLOAD_LOCATION + file for file in os.listdir(DOWNLOAD_LOCATION)
            if file.startswith(title)
        ][0]

        self.downloaded_videos['short_titles'].append(title_short)
        self.downloaded_videos['paths'].append(vid_path)

        self.download_label.setText(
            str(len(self.downloaded_videos['paths'])) + ' downloads')
        self.download_label.setStyleSheet("color: " + FOREGROUND_COLOR +
                                          "; background-color: " +
                                          BACKGROUND_COLOR +
                                          "; font-family: " + FONT + ";")

        self.download_selector.insertItem(0, title_short, vid_path)
        self.download_selector.setStyleSheet("color: " + FOREGROUND_COLOR +
                                             "; background-color: " +
                                             BACKGROUND_COLOR +
                                             "; font-family: " + FONT + ";")
        self.download_selector.setCurrentIndex(0)

        self.play_downloaded_button.setStyleSheet("color: " +
                                                  FOREGROUND_COLOR +
                                                  "; background-color: " +
                                                  BACKGROUND_COLOR +
                                                  "; border: 1px solid " +
                                                  FOREGROUND_COLOR +
                                                  "; font-family: " + FONT +
                                                  ";")
        self.play_downloaded_button.setCursor(Qt.PointingHandCursor)

    def on_home_clicked(self):

        if not (HOME_URL in self.history['urls'][-1]
                and self.history['page_numbers'][-1] == 1):
            print('loading homepage...')
            self.search = ''
            self.data = self.history['data'][0]
            self.history['data'].append(self.data)
            self.history['title_boxes'].append(self.data['page_title'])
            self.history['urls'].append(self.data['playlist_url'])
            self.history['page_numbers'].append(1)
            self.populate()
            groupbox = QGroupBox(self.data['page_title'])
            groupbox.setLayout(self.myform)
            groupbox.setStyleSheet("color: " + FOREGROUND_COLOR +
                                   "; font-family: " + FONT +
                                   ";font-style: italic")
            self.scroll.setWidget(groupbox)

            self.home_button.setStyleSheet("color: " + INACTIVE_COLOR +
                                           "; background-color: " +
                                           BACKGROUND_COLOR +
                                           "; border: 1px solid " +
                                           INACTIVE_COLOR + "; font-family: " +
                                           FONT + ";")
            self.home_button.setCursor(Qt.ArrowCursor)

        else:
            print('already home')

    def on_play_playlist_clicked(self):

        self.url = self.history['urls'][-1]
        self.player.play(self.url)

        #TODO: add mpv options to limit playlist items to number of search results

    def on_back_clicked(self):
        if len(self.history['urls']) > 1:
            #self.search = ''
            self.history['urls'].pop(-1)
            self.history['page_numbers'].pop(-1)
            self.history['data'].pop(-1)
            self.data = self.history['data'][-1]
            self.populate()
            self.history['title_boxes'].pop(-1)
            groupbox = QGroupBox(self.history['title_boxes'][-1])
            groupbox.setLayout(self.myform)
            groupbox.setStyleSheet("color: " + FOREGROUND_COLOR +
                                   "; font-family: " + FONT +
                                   ";font-style: italic")
            self.scroll.setWidget(groupbox)
            print('returning to page ' + self.history['urls'][-1] + '...')

            if len(self.history['urls']) == 1:
                for b in self.inactive_buttons:
                    b.setStyleSheet("color: " + INACTIVE_COLOR +
                                    "; background-color: " + BACKGROUND_COLOR +
                                    "; border: 1px solid " + INACTIVE_COLOR +
                                    "; font-family: " + FONT + ";")
                    b.setCursor(Qt.ArrowCursor)
            elif HOME_URL not in self.history['urls'][-1]:
                self.home_button.setStyleSheet("color: " + FOREGROUND_COLOR +
                                               "; background-color: " +
                                               BACKGROUND_COLOR +
                                               "; border: 1px solid " +
                                               FOREGROUND_COLOR +
                                               "; font-family: " + FONT + ";")
                self.home_button.setCursor(Qt.PointingHandCursor)
            else:
                self.home_button.setStyleSheet("color: " + INACTIVE_COLOR +
                                               "; background-color: " +
                                               BACKGROUND_COLOR +
                                               "; border: 1px solid " +
                                               INACTIVE_COLOR +
                                               "; font-family: " + FONT + ";")
                self.home_button.setCursor(Qt.ArrowCursor)
        else:
            print('could not go back')

    def on_play_downloaded(self):

        if len(self.downloaded_videos['paths']) > 0:
            self.player.play(self.download_to_play)

        else:
            print('no videos downloaded yet')

    def select_download(self, index):

        print('queued ' + self.download_selector.itemData(index))
        self.download_to_play = self.download_selector.itemData(index)

    def get_next_page(self):

        self.spinner.start()

        search_term = self.search

        try:
            sender = self.sender()
            if sender.page == '<':
                next_page_number = self.history['page_numbers'][-1] - 1
            elif sender.page == '>':
                next_page_number = self.history['page_numbers'][-1] + 1
            else:
                next_page_number = sender.page

        except:
            next_page_number = self.history['page_numbers'][-1] + 1

        self.history['page_numbers'].append(next_page_number)

        url = self.history['urls'][-1]
        self.history['urls'].append(url)
        title_box = re.sub(r' page \d+$', '', self.history['title_boxes'][-1])
        if next_page_number > 1:
            title_box = title_box[:29] + ' page ' + str(next_page_number)

        self.history['title_boxes'].append(title_box)

        data_limits = [
            NUM_RESULTS * (next_page_number - 1),
            NUM_RESULTS * next_page_number
        ]

        idx = 'get_next_page'
        worker = Worker(idx, url, search=False, limit=data_limits)
        thread = QThread()
        thread.setObjectName('thread_' + idx)
        self.__threads.append((thread, worker))
        worker.moveToThread(thread)

        worker.sig_data.connect(self.on_next_page_received)

        self.sig_abort_workers.connect(worker.abort)

        thread.started.connect(worker.grabData)
        thread.start()

    @pyqtSlot(dict)
    def on_next_page_received(self, data):

        search_term = self.search

        self.data = data

        self.history['data'].append(self.data)

        for b in self.inactive_buttons:
            b.setStyleSheet("color: " + FOREGROUND_COLOR +
                            "; background-color: " + BACKGROUND_COLOR +
                            "; border: 1px solid " + FOREGROUND_COLOR +
                            "; font-family: " + FONT + ";")
            b.setCursor(Qt.PointingHandCursor)

        self.populate()

        groupbox = QGroupBox(self.history['title_boxes'][-1])
        groupbox.setLayout(self.myform)
        groupbox.setStyleSheet("color: " + FOREGROUND_COLOR +
                               "; font-family: " + FONT +
                               ";font-style: italic")
        self.scroll.setWidget(groupbox)
        self.spinner.stop()

    @pyqtSlot()
    def abort_workers(self):
        self.sig_abort_workers.emit()
        for thread, worker in self.__threads:  # note nice unpacking by Python, avoids indexing
            thread.quit(
            )  # this will quit **as soon as thread event loop unblocks**
            thread.wait()  # <- so you need to wait for it to *actually* quit

        # even though threads have exited, there may still be messages on the main thread's
        # queue (messages that threads emitted before the abort):
        self.log.append('All threads exited')