class main_class(QWidget): def __init__(self): super().__init__() self.thread_subs = QThread() self.obj = thread_subtitles() self.obj.update_subtitles.connect(self.render_subtitles) self.obj.moveToThread(self.thread_subs) self.thread_subs.started.connect(self.obj.main) self.thread_subs.start() self.thread_translations = QThread() self.obj2 = thread_translations() self.obj2.get_translations.connect(self.render_popup) self.obj2.moveToThread(self.thread_translations) self.thread_translations.started.connect(self.obj2.main) self.thread_translations.start() # start the forms self.subtitles_base() self.subtitles_base2() self.popup_base() def clearLayout(self, layout): if layout == 'subs': layout = self.subtitles_vbox self.subtitles.hide() elif layout == 'subs2': layout = self.subtitles_vbox2 self.subtitles2.hide() elif layout == 'popup': layout = self.popup_vbox self.popup.hide() if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.deleteLater() else: self.clearLayout(item.layout()) def subtitles_base(self): self.subtitles = QFrame() self.subtitles.setAttribute(Qt.WA_TranslucentBackground) self.subtitles.setWindowFlags(Qt.X11BypassWindowManagerHint) self.subtitles.setStyleSheet(config.style_subs) self.subtitles_vbox = QVBoxLayout(self.subtitles) self.subtitles_vbox.setSpacing(config.subs_padding_between_lines) self.subtitles_vbox.setContentsMargins(0, 0, 0, 0) def subtitles_base2(self): self.subtitles2 = QFrame() self.subtitles2.setAttribute(Qt.WA_TranslucentBackground) self.subtitles2.setWindowFlags(Qt.X11BypassWindowManagerHint) self.subtitles2.setStyleSheet(config.style_subs) self.subtitles_vbox2 = QVBoxLayout(self.subtitles2) self.subtitles_vbox2.setSpacing(config.subs_padding_between_lines) self.subtitles_vbox2.setContentsMargins(0, 0, 0, 0) if config.pause_during_translation_B: self.subtitles2.enterEvent = lambda event: [ mpv_pause(), setattr(config, 'block_popup', False) ][0] self.subtitles2.leaveEvent = lambda event: [ mpv_resume(), setattr(config, 'block_popup', True) ][0] if not config.avoid_resuming else [ setattr(config, 'avoid_resuming', False), setattr(config, 'block_popup', True) ][0] def popup_base(self): self.popup = QFrame() self.popup.setAttribute(Qt.WA_TranslucentBackground) self.popup.setWindowFlags(Qt.X11BypassWindowManagerHint) self.popup.setStyleSheet(config.style_popup) self.popup_inner = QFrame() outer_box = QVBoxLayout(self.popup) outer_box.addWidget(self.popup_inner) self.popup_vbox = QVBoxLayout(self.popup_inner) self.popup_vbox.setSpacing(0) def render_subtitles(self, hide=False, redraw=False): if hide or not len(subs): try: self.subtitles.hide() self.subtitles2.hide() finally: return if redraw: self.subtitles.setStyleSheet(config.style_subs) self.subtitles2.setStyleSheet(config.style_subs) else: self.clearLayout('subs') self.clearLayout('subs2') if hasattr(self, 'popup'): self.popup.hide() # if subtitle consists of one overly long line - split into two if config.split_long_lines_B and len( subs.split('\n')) == 1 and len(subs.split( ' ')) > config.split_long_lines_words_min - 1: subs2 = split_long_lines(subs) else: subs2 = subs subs2 = re.sub(' +', ' ', subs2).strip() ############################## for line in subs2.split('\n'): line2 = ' %s ' % line.strip() ll = drawing_layer(line2, subs2) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) hbox.addStretch() hbox.addWidget(ll) hbox.addStretch() self.subtitles_vbox.addLayout(hbox) #################################### hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) hbox.addStretch() if config.R2L_from_B: line2 = line2[::-1] line2 += '\00' word = '' for smbl in line2: if smbl.isalpha(): word += smbl else: if len(word): if config.R2L_from_B: word = word[::-1] ll = events_class(word, subs2) ll.mouseHover.connect(self.render_popup) ll.redraw.connect(self.render_subtitles) hbox.addWidget(ll) word = '' if smbl != '\00': ll = events_class(smbl, subs2, skip=True) hbox.addWidget(ll) hbox.addStretch() self.subtitles_vbox2.addLayout(hbox) self.subtitles.adjustSize() self.subtitles2.adjustSize() w = self.subtitles.geometry().width() h = self.subtitles.height = self.subtitles.geometry().height() x = (config.screen_width / 2) - (w / 2) if config.subs_top_placement_B: y = config.subs_screen_edge_padding else: y = config.screen_height - config.subs_screen_edge_padding - h self.subtitles.setGeometry(int(x), int(y), 0, 0) self.subtitles.show() self.subtitles2.setGeometry(int(x), int(y), 0, 0) self.subtitles2.show() def render_popup(self, text, x_cursor_pos, is_line): if text == '': if hasattr(self, 'popup'): self.popup.hide() return self.clearLayout('popup') if is_line: QApplication.setOverrideCursor(Qt.WaitCursor) line = globals()[config.translation_function_name_full_sentence]( text) if config.translation_function_name_full_sentence == 'google': try: line = line[0][0][0].strip() except: line = 'Google translation failed.' if config.split_long_lines_B and len( line.split('\n')) == 1 and len(line.split( ' ')) > config.split_long_lines_words_min - 1: line = split_long_lines(line) ll = QLabel(line) ll.setObjectName("first_line") self.popup_vbox.addWidget(ll) else: word = text for translation_function_name_i, translation_function_name in enumerate( config.translation_function_names): pairs, word_descr = globals()[translation_function_name](word) if not len(pairs): pairs = [['', '[Not found]']] #return # ~pairs = [ [ str(i) + ' ' + pair[0], pair[1] ] for i, pair in enumerate(pairs) ] if word in config.scroll: if len(pairs[config.scroll[word]:] ) > config.number_of_translations: pairs = pairs[config.scroll[word]:] else: pairs = pairs[-config.number_of_translations:] if len(config.translation_function_names) == 1: config.scroll[word] -= 1 for i1, pair in enumerate(pairs): if i1 == config.number_of_translations: break if config.split_long_lines_in_popup_B: pair[0] = split_long_lines( pair[0], max_symbols_per_line=config. split_long_lines_in_popup_symbols_min) pair[1] = split_long_lines( pair[1], max_symbols_per_line=config. split_long_lines_in_popup_symbols_min) if pair[0] == '-': pair[0] = '' if pair[1] == '-': pair[1] = '' # ~if config.R2L_from_B: # ~pair[0] = pair[0][::-1] # ~if config.R2L_to_B: # ~pair[1] = pair[1][::-1] if pair[0] != '': # to emphasize the exact form of the word # to ignore case on input and match it on output chnks = re.split(word, pair[0], flags=re.I) exct_words = re.findall(word, pair[0], flags=re.I) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) for i2, chnk in enumerate(chnks): if len(chnk): ll = QLabel(chnk) ll.setObjectName("first_line") hbox.addWidget(ll) if i2 + 1 < len(chnks): ll = QLabel(exct_words[i2]) ll.setObjectName("first_line_emphasize_word") hbox.addWidget(ll) # filling the rest of the line with empty bg ll = QLabel() ll.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) hbox.addWidget(ll) self.popup_vbox.addLayout(hbox) if pair[1] != '': ll = QLabel(pair[1]) ll.setObjectName("second_line") self.popup_vbox.addWidget(ll) # padding ll = QLabel() ll.setStyleSheet("font-size: 6px;") self.popup_vbox.addWidget(ll) if len(word_descr[0]): ll = QLabel(word_descr[0]) ll.setProperty("morphology", word_descr[1]) ll.setAlignment(Qt.AlignRight) self.popup_vbox.addWidget(ll) # delimiter between dictionaries if translation_function_name_i + 1 < len( config.translation_function_names): ll = QLabel() ll.setObjectName("delimiter") self.popup_vbox.addWidget(ll) self.popup_inner.adjustSize() self.popup.adjustSize() w = self.popup.geometry().width() h = self.popup.geometry().height() if w > config.screen_width: w = config.screen_width - 20 if not is_line: if w < config.screen_width / 3: w = config.screen_width / 3 if x_cursor_pos == -1: x = (config.screen_width / 2) - (w / 2) else: x = x_cursor_pos - w / 5 if x + w > config.screen_width: x = config.screen_width - w if config.subs_top_placement_B: y = self.subtitles.height + config.subs_screen_edge_padding else: y = config.screen_height - config.subs_screen_edge_padding - self.subtitles.height - h self.popup.setGeometry(int(x), int(y), int(w), 0) self.popup.show() QApplication.restoreOverrideCursor()