class Delegate(QStyledItemDelegate): def __init__(self, parent=None): super(Delegate, self).__init__(parent=None) self.parent = parent self.waiting_movie = QMovie(resource('waiting.gif')) self.waiting_movie.setCacheMode(True) self.waiting_movie.frameChanged.connect(self.on_frame_changed) self.sync_movie = QMovie(resource('sync.gif')) self.sync_movie.setCacheMode(True) self.sync_movie.frameChanged.connect(self.on_frame_changed) def on_frame_changed(self): values = self.parent.model().status_dict.values() if 0 in values or 1 in values: self.parent.viewport().update() else: self.waiting_movie.setPaused(True) self.sync_movie.setPaused(True) def paint(self, painter, option, index): column = index.column() if column == 1: pixmap = None status = index.data(Qt.UserRole) if not status: # "Loading..." self.waiting_movie.setPaused(False) pixmap = self.waiting_movie.currentPixmap().scaled(20, 20) elif status == 1: # "Syncing" self.sync_movie.setPaused(False) pixmap = self.sync_movie.currentPixmap().scaled(20, 20) if pixmap: point = option.rect.topLeft() painter.drawPixmap(QPoint(point.x(), point.y() + 5), pixmap) option.rect = option.rect.translated(pixmap.width(), 0) super(Delegate, self).paint(painter, option, index)
class App(QWidget): def __init__(self): super().__init__() self.title = 'e-pet' self.left = 100 self.top = 100 self.width = 640 self.height = 480 self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) # Create widget label = QLabel(self) # pixmap = QPixmap('../pic/cheer.gif') # label.setPixmap(pixmap) self.gif = QMovie('./img/cheers.gif') pixmap = self.gif.currentPixmap() self.gif.frameChanged.connect(self.onNextFrame) label.setMovie(self.gif) self.gif.start() self.resize(pixmap.width(), pixmap.height()) self.setMask(pixmap.mask()) # 设置窗体无边框 self.setWindowFlags(Qt.FramelessWindowHint) # 设置窗口置顶 self.setWindowFlags(Qt.WindowStaysOnTopHint) # 设置背景透明 self.setAttribute(Qt.WA_TranslucentBackground) self.show() def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.m_flag = True self.m_Position = event.globalPos() - self.pos() event.accept() self.setCursor(QCursor(Qt.OpenHandCursor)) def mouseMoveEvent(self, QMouseEvent): if Qt.LeftButton and self.m_flag: self.move(QMouseEvent.globalPos() - self.m_Position) QMouseEvent.accept() def mouseReleaseEvent(self, QMouseEvent): self.m_flag = False self.setCursor(QCursor(Qt.ArrowCursor)) def onNextFrame(self): pixmap = self.gif.currentPixmap() # self.setPixmap(pixmap) self.setMask(pixmap.mask())
def _load_movie(self, movie: QMovie, keep_zoom: bool) -> None: """Load new movie into the graphics scene.""" movie.jumpToFrame(0) if api.settings.image.autoplay.value: movie.start() widget = QLabel() widget.setMovie(movie) self._update_scene(widget, QRectF(movie.currentPixmap().rect()), keep_zoom) widget.resize(movie.currentPixmap().size())
class MainWindow(QMainWindow): my_signal = pyqtSignal() def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) global file, pagecount, total, enabler, option file = "" pagecount = 0 total = 0.0 option = "" self.setWindowTitle("Printing Booth Systems") self.movie = QMovie("menu.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() self.btn = QPushButton('Touch here to Begin', self) self.btn.setGeometry(200, 230, 400, 100) self.btn.setFont(QFont('Arial', 30)) self.btn.clicked.connect(self.slot_btn_function) def paintEvent(self, event): currentFrame = self.movie.currentPixmap() frameRect = currentFrame.rect() frameRect.moveCenter(self.rect().center()) if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame) def slot_btn_function(self): self.fs = FileSelect() self.fs.showFullScreen() self.movie.stop() self.hide()
class SystemTrayIcon(QSystemTrayIcon): def __init__(self, parent): super(SystemTrayIcon, self).__init__() self.parent = parent self.new_folder_window = NewFolderWindow(parent) self.preferences_window = PreferencesWindow() self.setIcon(QIcon(":gridsync.png")) self.right_menu = RightClickMenu(self) self.setContextMenu(self.right_menu) self.activated.connect(self.on_click) self.animation = QMovie() self.animation.setFileName(":sync.gif") self.animation.updated.connect(self.update_animation_frame) self.animation.setCacheMode(True) def update_animation_frame(self): self.setIcon(QIcon(self.animation.currentPixmap())) def set_icon(self, resource): self.setIcon(QIcon(resource)) def on_click(self, value): #self.right_menu.populate() if value == QSystemTrayIcon.Trigger: open_gridsync_folder() def on_quit(self): reactor.stop()
class SystemTrayIcon(QSystemTrayIcon): def __init__(self, parent): super(SystemTrayIcon, self).__init__() self.parent = parent self.icon = QIcon(resource(settings['application']['tray_icon'])) self.setIcon(self.icon) self.menu = Menu(self) self.setContextMenu(self.menu) self.activated.connect(self.on_click) self.animation = QMovie() self.animation.setFileName( resource(settings['application']['tray_icon_sync'])) self.animation.updated.connect(self.update) self.animation.setCacheMode(True) def update(self): if self.parent.core.operations: self.animation.setPaused(False) self.setIcon(QIcon(self.animation.currentPixmap())) else: self.animation.setPaused(True) self.setIcon(self.icon) def on_click(self, value): if value == QSystemTrayIcon.Trigger and sys.platform != 'darwin': self.parent.show_main_window()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setGeometry(50, 50, 600, 750) self.setFixedSize(500, 200) self.startUIWindow() #Tạo file load trên dev self.movie = QMovie("id-loading-5.gif") #Tạo load trong software cài đặt #self.movie = QMovie('\link') self.movie.frameChanged.connect(self.repaint) self.movie.start() def startUIWindow(self): self.Window = UIWindow(self) self.setWindowTitle("Processing database, please wait ...") self.show() def paintEvent(self, event): currentFrame = self.movie.currentPixmap() frameRect = currentFrame.rect() frameRect.moveCenter(self.rect().center()) if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame)
class AboutWindow(QMainWindow): """ About window - names """ def __init__(self): super().__init__() self.setGeometry(1000, 800, 1000, 800) self.setWindowTitle('About') self.movie = QMovie("giphy.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() self.init_text() def paintEvent(self, event): """ This function repaint the event over and over (animation) """ currentFrame = self.movie.currentPixmap() frameRect = currentFrame.rect() frameRect.moveCenter(self.rect().center()) if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame) def init_text(self): """ text init """ text_to_show = 'Names: Roy Jan, Ronen Rozen, Yuval Bar-Nahor, Ricky Danipog\nLaProfessor: Itzhak Aviv' label = QLabel(text_to_show, self) label.setGeometry(50, 50, 900, 100)
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) #self.setGeometry(50, 50, 600, 750) self.setGeometry(50, 50, 50, 50) #self.setFixedSize(600, 750) self.setFixedSize(250, 250) #self.startUIWindow() self.movie = QMovie("/home/pi/Documents/TZcL7Cc.gif") self.movie.frameChanged.connect(self.repaint) def start(self): self.startUIWindow() self.movie.start() def startUIWindow(self): self.Window = UIWindow(self) self.setWindowTitle("My Program") self.show() def paintEvent(self, event): currentFrame = self.movie.currentPixmap() frameRect = currentFrame.rect() frameRect.moveCenter(self.rect().center()) if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame)
def dealFile_set_icon(self, b): if b: gif_icon = QMovie(r'static\pic\download.gif') gif_icon.frameChanged.connect( lambda: self.setIcon(QIcon(gif_icon.currentPixmap()))) gif_icon.start() else: self.setIcon(self.base_icon)
class App(QWidget): def __init__(self, success): super().__init__() self.title = 'PDF Merger' self.setWindowIcon(QIcon("C:\\Users\\cold\\Downloads\\pdf_icon.png")) self.left = 100 self.top = 100 self.width = 600 self.height = 600 self.fileNames = [] self.showSuccess = success self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.movie = QMovie("C:\\Users\\cold\\Downloads\\cats.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() buttonGetFiles = QPushButton('Choose PDFs to Merge', self) buttonGetFiles.resize(200, 32) buttonGetFiles.move(200, 300) buttonGetFiles.clicked.connect(self.openFileDialog) if self.showSuccess: explText = QLabel(self) explText.setText("Success! File created.") explText.setGeometry(190, 100, 240, 32) explText.setStyleSheet('color: green; font: 18pt Arial') self.show() def openFileDialog(self): options = QFileDialog.Options() fileNamesFromDialog, _ = QFileDialog.getOpenFileNames( self, "Open Files (ctrl + click or shift + click to get multiple files)", "", "PDF Files (*.pdf);;All Files (*)", options=options) if fileNamesFromDialog: for filename in fileNamesFromDialog: self.fileNames.append(filename) self.cams = filesChosen(self.fileNames) self.cams.show() self.close() def paintEvent(self, event): currentFrame = self.movie.currentPixmap() frameRect = currentFrame.rect() frameRect.moveCenter(self.rect().center()) if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame)
class _Loading(QSplashScreen): """A splashscreen to show while loading TensorFlow.""" def __init__(self): """Class constructor. Loads a gif to show while loading.""" path = os.path.join('res', 'loading', 'loading.gif') self._gif = QMovie(path) self._gif.jumpToFrame(0) super().__init__(self._gif.currentPixmap(), Qt.WindowStaysOnTopHint) self.showMessage('Loading, please wait...', color=Qt.yellow) self._gif.frameChanged.connect(self._update) self.setFixedSize(self.pixmap().size()) self._gif.start() self.show() def mousePressEvent(self, event: QMouseEvent): """Override the method so the splashscreen won't go away by clicking.""" def _update(self): self.setPixmap(self._gif.currentPixmap())
class Delegate(QStyledItemDelegate): def __init__(self, parent=None): super().__init__(parent=None) self.parent = parent self.waiting_movie = QMovie(resource("waiting.gif")) self.waiting_movie.setCacheMode(True) self.waiting_movie.frameChanged.connect(self.on_frame_changed) self.sync_movie = QMovie(resource("sync.gif")) self.sync_movie.setCacheMode(True) self.sync_movie.frameChanged.connect(self.on_frame_changed) def on_frame_changed(self): values = self.parent.model().status_dict.values() if (MagicFolderChecker.LOADING in values or MagicFolderChecker.SYNCING in values or MagicFolderChecker.SCANNING in values): self.parent.viewport().update() else: self.waiting_movie.setPaused(True) self.sync_movie.setPaused(True) def paint(self, painter, option, index): column = index.column() if column == 1: pixmap = None status = index.data(Qt.UserRole) if status == MagicFolderChecker.LOADING: self.waiting_movie.setPaused(False) pixmap = self.waiting_movie.currentPixmap().scaled( 20, 20, Qt.KeepAspectRatio, Qt.SmoothTransformation) elif status in ( MagicFolderChecker.SYNCING, MagicFolderChecker.SCANNING, ): self.sync_movie.setPaused(False) pixmap = self.sync_movie.currentPixmap().scaled( 20, 20, Qt.KeepAspectRatio, Qt.SmoothTransformation) if pixmap: point = option.rect.topLeft() painter.drawPixmap(QPoint(point.x(), point.y() + 5), pixmap) option.rect = option.rect.translated(pixmap.width(), 0) super().paint(painter, option, index)
class SplashScreen(QSplashScreen): def __init__(self, animation, flags): QSplashScreen.__init__(self, QPixmap(), flags) self.movie = QMovie(animation) self.movie.frameChanged.connect(self.onNextFrame) self.movie.start() @pyqtSlot() def onNextFrame(self): pixmap = self.movie.currentPixmap() self.setPixmap(pixmap) self.setMask(pixmap.mask())
class GifSplashScreen(QSplashScreen): def __init__(self, *args, **kwargs): super(GifSplashScreen, self).__init__(*args, **kwargs) self.movie = QMovie('image/splash.gif') self.movie.frameChanged.connect(self.onFrameChanged) self.movie.start() def onFrameChanged(self, _): self.setPixmap(self.movie.currentPixmap()) def finish(self, widget): self.movie.stop() super(GifSplashScreen, self).finish(widget)
class MySplashScreen(QSplashScreen): def __init__(self, animation, flags): # run event dispatching in another thread QSplashScreen.__init__(self, QPixmap(), flags) self.movie = QMovie(animation) self.movie.frameChanged.connect(self.onNextFrame) #self.connect(self.movie, SIGNAL('frameChanged(int)'), SLOT('onNextFrame()')) self.movie.start() def onNextFrame(self): pixmap = self.movie.currentPixmap() self.setPixmap(pixmap) self.setMask(pixmap.mask())
class SplashScreen(QSplashScreen): def __init__(self, animation, flags, msg=''): QSplashScreen.__init__(self, QPixmap(), flags) self.movie = QMovie(animation) self.movie.setCacheMode(QMovie.CacheAll) self.movie.frameChanged.connect(self.onNextFrame) self.movie.start() self.showMessage(msg, Qt.AlignBottom | Qt.AlignCenter, Qt.white) self.show() @pyqtSlot() def onNextFrame(self): pixmap = self.movie.currentPixmap() self.setPixmap(pixmap) #self.setMask(pixmap.mask())
class MySplashScreen(QSplashScreen): def __init__(self, animation, flags): # run event dispatching in another thread QSplashScreen.__init__(self, QPixmap(), flags) qtRectangle = self.frameGeometry() centerPoint = QDesktopWidget().availableGeometry().center() qtRectangle.moveCenter(centerPoint) self.move(qtRectangle.topLeft()) self.movie = QMovie(animation) self.movie.frameChanged.connect(self.onNextFrame) self.movie.start() @pyqtSlot() def onNextFrame(self): pixmap = self.movie.currentPixmap() self.setPixmap(pixmap) self.setMask(pixmap.mask())
class CaptureAreaDialog(QDialog): def __init__(self, parent=None, dialog=0): """ init CaptureAreaDialog module """ super(CaptureAreaDialog, self).__init__(parent) self.setModal(True) self.resize(QSize(600, 430)) self.setFixedSize(QSize(600, 430)) self.label = QLabel(self) self.label.setWordWrap(True) self.label.setFont(QFont("MS Shell Dlg 2", 10, QFont.Bold)) self.label.setGeometry(20, 357, 390, 53) if dialog == 0: self.label.setText( "Manually capture the area by drag & drop the top left " + "corner of the canvas to the bottom right corner.") self.movie = QMovie(":/gifs/capture_canvas.gif") else: self.label.setText( "Manually capture the area by drag & drop the top left " + "corner of the painting controls area to the bottom right corner.") self.movie = QMovie(":/gifs/capture_ctrl_area.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() self.ok_button = QPushButton(self) self.ok_button.setText("OK") self.ok_button.setGeometry(430, 357, 150, 53) self.ok_button.clicked.connect(self.ok_clicked) def paintEvent(self, event): """ Update the gif """ currentFrame = self.movie.currentPixmap() frameRect = currentFrame.rect() if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame) def ok_clicked(self): """ Ok has been clicked, return 1 """ self.done(1)
class SystemTrayIcon(QSystemTrayIcon): def __init__(self, gui): super(SystemTrayIcon, self).__init__() self.gui = gui tray_icon_path = resource(settings['application']['tray_icon']) self.app_pixmap = QPixmap(tray_icon_path) self.app_icon = QIcon(tray_icon_path) self.setIcon(self.app_icon) self.menu = Menu(self.gui) self.setContextMenu(self.menu) self.activated.connect(self.on_click) self.messageClicked.connect(self.gui.show_main_window) self.animation = QMovie() self.animation.setFileName( resource(settings['application']['tray_icon_sync'])) self.animation.updated.connect(self.update) self.animation.setCacheMode(True) def update(self): if self.gui.core.operations: self.animation.setPaused(False) pixmap = self.animation.currentPixmap() if self.gui.unread_messages: pixmap = BadgedPixmap( pixmap, len(self.gui.unread_messages), 0.6 ) self.setIcon(QIcon(pixmap)) else: self.animation.setPaused(True) if self.gui.unread_messages: self.setIcon(QIcon(BadgedPixmap( self.app_pixmap, len(self.gui.unread_messages), 0.6 ))) else: self.setIcon(self.app_icon) def on_click(self, value): if value == QSystemTrayIcon.Trigger and sys.platform != 'darwin': self.gui.show_main_window()
class Game (QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.resize(800, 336) Server.center(self) self.setWindowTitle("Welcome") self.enter = QPushButton("enter", self) self.enter.move(360,280) self.enter.resize(80, 25) self.enter.clicked.connect(self.gameMenu) self.enter.setStyleSheet("background-color: rgb(240,255,255); font: bold 15px; color: black;") # create background animated gif self.movie = QMovie("textures/Background/Red.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() # select the music track pygame.mixer.music.load(playlist["Track 5"]) # loops the music pygame.mixer.music.play(-1, 0.0) self.show() def gameMenu(self): self.startM = start_Menu() self.movie.stop() self.close() def paintEvent(self, event): # after every changed image, refresh the background with the currentPixmap painter = QPainter(self) pixmap = self.movie.currentPixmap() self.setMask(pixmap.mask()) painter.drawPixmap(0, 0, pixmap)
class ArcaneSplashScreen(QSplashScreen): """Arcane splashscreen. Shows gif while starting the application.""" def __init__(self, animation): module_logger.info("Inside 'ArcaneSplashScreen' constructor.") QSplashScreen.__init__(self, QPixmap()) self.movie = QMovie(animation) self.movie.frameChanged.connect(self.onNextFrame) self.movie.start() module_logger.info("Done.") #slot def onNextFrame(self): pixmap = self.movie.currentPixmap() # returns current frame self.setPixmap(pixmap) self.setMask(pixmap.mask()) #causes only frame to be visible ie transparent, depending upon the system
class DesktopWindow(QWidget): def __init__(self): super().__init__() self.ebutoon = QPushButton(self) self.ebutoon.setIcon(QIcon("pictures/exit_pic.png")) self.ebutoon.setIconSize(QSize(50, 50)) self.ebutoon.move(1860, 0) self.ebutoon.clicked.connect(QCoreApplication.instance().quit) self.showFullScreen() self.movie = QMovie("pictures/background.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() def paintEvent(self, event): current_frame = self.movie.currentPixmap() frame_rect = current_frame.rect() frame_rect.moveCenter(self.rect().center()) if frame_rect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frame_rect.left(), frame_rect.top(), current_frame)
class IconManagement(object): def __init__(self, tray, interval = 100): self.tray = tray self.movie = QMovie(":/images/tray_animations/tray.gif") self.movie.setSpeed(interval) self.movie.frameChanged.connect(self.next_icon) self.icons = Enum( ok = QIcon(":/images/demerio.png"), problem = QIcon(":/images/demerio-problem.png"), conductor_problem = QIcon(":/images/demerio-conductor-problem.png") ) self.icon = self.icons.ok self.update_icon() def internet_is_ok(self, internet_is_ok): self.icon = self.icons.ok if internet_is_ok else self.icons.problem self.update_icon() @pyqtSlot(int) def next_icon(self, i): self.tray.setIcon(QIcon(self.movie.currentPixmap())) def start(self): self.movie.start() def stop(self): self.update_icon() self.movie.stop() def update_icon(self): self.tray.setIcon(self.icon) def conductor_problem(self): if self.movie.state() == QMovie.Running: self.movie.stop() self.icon = self.icons.conductor_problem self.update_icon()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setGeometry(50, 50, 300, 500) self.setFixedSize(600, 750) self.startUItab() self.movie = QMovie("giphy.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() def startUItab(self): self.Window = UItab(self) self.setWindowTitle("GiF work") self.show() def PaintEvent(self, event): currentFrame = self.movie.currentPixmap() framerect = currentFrame.rect() framerect.moveCenter(self.rect().center()) if framerect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(framerect.left(), framerect.top(), currentFrame)
class VentanaFinal(QWidget): def __init__(self, *args): super().__init__(*args) def crear_pantalla(self, resultado): if resultado == "victoria": self.ruta = ruta_victoria self.ruta_sonido = ruta_sonido_victoria titulo = '¡Victoria!' else: self.ruta = ruta_derrota self.ruta_sonido = ruta_sonido_derrota titulo = 'Derrota :(' self.setWindowTitle(titulo) self.label_usuario = QLabel() self.movie = QMovie(self.ruta) self.movie.frameChanged.connect(self.repaint) self.movie.start() self.sonido() self.show() def sonido(self): self.soundtrack = QSound(self.ruta_sonido) self.soundtrack.play() self.soundtrack.setLoops(1000) def paintEvent(self, event): frame_actual = self.movie.currentPixmap() frameRect = frame_actual.rect() frameRect.moveCenter(self.rect().center()) if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), frame_actual)
class IconManagement(object): def __init__(self, tray, interval=100): self.tray = tray self.movie = QMovie(":/images/tray_animations/tray.gif") self.movie.setSpeed(interval) self.movie.frameChanged.connect(self.next_icon) self.icons = Enum( ok=QIcon(":/images/demerio.png"), problem=QIcon(":/images/demerio-problem.png"), conductor_problem=QIcon(":/images/demerio-conductor-problem.png")) self.icon = self.icons.ok self.update_icon() def internet_is_ok(self, internet_is_ok): self.icon = self.icons.ok if internet_is_ok else self.icons.problem self.update_icon() @pyqtSlot(int) def next_icon(self, i): self.tray.setIcon(QIcon(self.movie.currentPixmap())) def start(self): self.movie.start() def stop(self): self.update_icon() self.movie.stop() def update_icon(self): self.tray.setIcon(self.icon) def conductor_problem(self): if self.movie.state() == QMovie.Running: self.movie.stop() self.icon = self.icons.conductor_problem self.update_icon()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setGeometry(50, 50, 600, 750) self.setFixedSize(500, 500) self.startUIWindow() self.movie = QMovie("mail.gif") self.movie.frameChanged.connect(self.repaint) self.movie.start() def startUIWindow(self): self.Window = UIWindow(self) self.setWindowTitle("Email Dialog") self.show() def paintEvent(self, event): currentFrame = self.movie.currentPixmap() frameRect = currentFrame.rect() frameRect.moveCenter(self.rect().center()) if frameRect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame)
class App(QWidget): def __init__(self): super().__init__() self.setWindowTitle('The Seeker of fire') self.showFullScreen() self.Text = QLabel(self) self.book = QLabel(self) self.location = QLabel(self) self.changed = False self.action_targ = QLabel(self) self.action_targ.resize(self.width() / 12, 10) self.action_targ.move(0, 0) self.action_targ.setStyleSheet('QLabel {background-color: Red;' 'border-radius: 5px }') self.targ_pos = [(self.width() / 2.17, self.height() / 2.5 - 20), (self.width() / 2.9, self.height() / 2.5 - 20), (self.width() / 1.75, self.height() / 2.5 - 20)] self.the_right_answer = [False, False, False] self.ur_damage = 10 self.e_damage = 0 self.HP_points = 100 self.eHP_points = 100 self.result = False self.cursor = QCursor(QPixmap('cursor_3.png')) self.cursor.pixmap() self.setCursor(self.cursor) self.skip = QPushButton(self) self.skip.resize(100, 20) self.skip.move(self.width() / 2 + 180, self.height() / 4 + self.height() / 16 + 20) self.skip.setText('SKIP') self.skip.setStyleSheet( 'QPushButton {background-color: rgba(10, 20, 100, 0.2)}' 'QPushButton:hover {background-color: Red}') self.read = True self.skip.clicked.connect(self.next) melody = 'DS2.wav' self.playable = QSound(melody) self.playable.play() melody2 = 'in_battle.wav' self.playable2 = QSound(melody2) self.next_melody = False self.movie = QMovie("fire_3.gif") self.movie.setScaledSize(QSize(self.width(), self.height())) self.movie.frameChanged.connect(self.repaint) self.movie.start() self.NPC_enemy = QLabel(self) self.NPC_enemy.resize(self.height() / 5, self.height() / 5) self.NPC_enemy.move(self.width() / 2.3, self.height() / 16) self.NPC_enemy.setStyleSheet( "QLabel {color: rgb(0, 0, 51);" 'background-color: rgba(10, 20, 100, 0.2);' 'border-color: rgba(100, 100, 100, 0.5);' 'border-style: solid;' 'border-width: 2px;' '}' 'QLabel:hover {background-color: rgba(100, 0, 0, 0.7)}') self.book.resize(self.width() / 3, self.height() / 16) self.book.move(self.width() / 3, self.height() / 4 + 40) self.book.setStyleSheet( "QLabel {background-color: rgba(100, 40, 51, 0.5);" "text-align: center }") self.book.setFont(QFont('Times New Roman', 12)) self.attack = QPushButton(self) self.defend = QPushButton(self) self.dodge = QPushButton(self) self.change_size('attack_proj.png', (int(self.width() / 12), int(self.height() / 4))) self.change_size('shield.png', (int(self.width() / 12), int(self.height() / 4))) self.change_size('dodging.png', (int(self.width() / 12), int(self.height() / 4))) self.attack.setStyleSheet( 'QPushButton {background-color: rgba(10, 20, 100, 0.2);' 'border-color: rgb(10, 20, 100,);' 'border-style: solid;' 'border-width: 5px;' 'border-radius: 40px;' 'background-image: url(attack_proj.png)' '}' 'QPushButton:pressed {background-image: url(DS3.jpg)}') self.attack.resize(self.width() / 12, self.height() / 4) self.attack.move(self.width() / 2.17, self.height() / 2.5) self.attack.clicked.connect(self.attack_fnc) self.defend.setStyleSheet( 'QPushButton {background-color: rgba(10, 20, 100, 0.2);' 'border-color: rgb(10, 20, 100,);' 'border-style: solid;' 'border-width: 5px;' 'border-radius: 40px;' 'background-image: url(shield.png)' '}' 'QPushButton:pressed {background-image: url(DS3.jpg)}') self.defend.resize(self.width() / 12, self.height() / 4) self.defend.move(self.width() / 2.9, self.height() / 2.5) self.defend.clicked.connect(self.defend_fnc) self.dodge.setStyleSheet( 'QPushButton {background-color: rgba(10, 20, 100, 0.2);' 'border-color: rgb(10, 20, 100,);' 'border-style: solid;' 'border-width: 5px;' 'border-radius: 40px;' 'background-image: url(dodging.png)' '}' 'QPushButton:pressed {background-image: url(DS3.jpg)}') self.dodge.resize(self.width() / 12, self.height() / 4) self.dodge.move(self.width() / 1.75, self.height() / 2.5) self.dodge.clicked.connect(self.dodge_fnc) self.Text.move(self.width() / 3, 0) self.Text.resize(self.width() / 3, self.height()) self.Text.move(self.width() / 3, 0) self.Text.setStyleSheet( "QLabel {color: rgb(0, 0, 51);" 'font-family: "Times New Roman", Georgia, Serif;' 'font-size: 25px;' 'background-color: rgba(10, 20, 100, 0.2);' 'border-color: rgb(10, 20, 100,);' 'border-style: solid;' 'border-width: 5px' '}') self.HP = QProgressBar(self) self.HP.resize(self.width() / 3, 30) self.HP.move(self.width() / 3, self.height() * 0) self.HP.setStyleSheet( "QProgressBar{border: 1px solid transparent;text-align: center;" "color:rgba(255,255,250,0);" "border-radius: 10px;" "border-width: 8px;" "border-image: 9,2,5,2; " "background-color: Grey;" "}" "QProgressBar::chunk {background-color: qlineargradient(x1: 0, " "y1: 0, x2: 0, y2: 1, stop: 0 rgba(100,80,50,1), stop: 1 rgba(255,0,0,1));" "border-radius: 5px}") self.HP.setValue(self.HP_points) self.eHP = QProgressBar(self) self.eHP.resize(self.width() / 6, 10) self.eHP.setStyleSheet( "QProgressBar{border: 1px solid transparent;text-align: center;" "color:rgba(255,255,250,0);" "border-radius: 10px;" "border-width: 8px;" "border-image: 9,2,5,2; " "background-color: Grey" "}" "QProgressBar::chunk {background-color: qlineargradient(x1: 0, " "y1: 0, x2: 0, y2: 1, stop: 0 rgba(100,80,50,100), stop: 1 rgba(255,0,0,255));" "border-radius: 5px}") self.eHP.move(self.width() / 2.45, self.width() / 6.5) self.close_button = QPushButton(self) self.close_button.resize(self.width() / 4, self.height() / 20) self.close_button.move(self.width() / 3 + self.width() / 24, self.height() / 1.07) self.close_button.setStyleSheet( 'QPushButton {border: 3px solid;' 'border-radius: 10px;' 'background-color: Khaki' '}' 'QPushButton:pressed{border: 1px solid;' 'border-radius: 40px;' 'background-color: Red' '}' 'QPushButton:hover{background-color: rgba(255, 0, 0, 40)}') self.close_button.clicked.connect(self.close_event) self.close_button.setFont(QFont('Times New Roman', 20)) self.close_button.setText('Выход') self.location.resize(self.width() / 3, self.height() / 8) self.location.move(self.width() / 3, self.height() / 4) self.location.setFont(QFont('Times New Roman', 20)) self.location.setText('ЗАБРОШЕННЫЕ МОГИЛЫ') self.location.setStyleSheet( "QLabel {background-color: rgba(250, 40, 51, 0.5);" "}") self.location.setAlignment(Qt.AlignCenter) self.game() def next(self): self.read = False def paintEvent(self, event): currentframe = self.movie.currentPixmap() framerect = currentframe.rect() framerect.moveCenter(self.rect().center()) if framerect.intersects(event.rect()): painter = QPainter(self) painter.drawPixmap(framerect.left(), framerect.top(), currentframe) def close_event(self): self.close() def game(self): dont_stop = threading.Thread(target=self.always_on) screen = threading.Thread(target=self.on_screen) screen.start() dont_stop.start() def on_screen(self): self.HP.show() self.close_button.show() self.Text.show() self.book.show() self.NPC_enemy.show() self.skip.show() self.attack.show() self.defend.show() self.dodge.show() self.eHP.show() self.write('И в самом деле. Замок, что зовётся Лотриком, ') self.write('стоит там, где сходятся земли Повелителей пепла. ') self.write( 'Покоряя север, пилигримы убеждаются, что старые сказания не лгут') self.write('Огонь затухает, и повелители пепла покидают свои троны') self.write('Когда огонь под угрозой, когда звонит колокол,') self.write(' Повелители пепла поднимаются из своих могил.') self.write('Олдрик, святой покровитель глубин.') self.write('Легион нежити Фаррона, Хранители Бездны') self.write( 'И мрачный правитель из осквернённой столицы - гигант Йорм.') self.write( 'Но в действительности... Повелители оставят свои троны, и негорящие восстанут.' ) self.write('Безымянная, проклятая нежить, недостойная стать пеплом.') self.write('И стало так. Негорящие всегда ищут угли.') self.location.show() time.sleep(2) self.location.close() self.write('Вы поднимаетесь из могилы. В руках у вас ваш меч. ') self.write('Вы чётко знате, что будуте делать дальше') self.write('Вам предстоит вернуть повелителей на свои троны и спасти ') self.write('угасающий мир от погружения во тьму') self.write('Перед вами тропа') self.write('Пути назад больше нет') self.write('...') self.write('Вы идете по тропе') self.write( 'Перед вами Полый, нежить, потерявшая рассудок и навеки лишившаяся ' ) self.write('возможности прикоснуться к Огню') self.write('Полый достает меч') self.write('Приготовьтесь к битве') self.write(' ') self.NPC_enemy.close() self.NPC_enemy.setStyleSheet( 'QLabel { background-image: url(hollow.jpg)}') time.sleep(0.3) self.NPC_enemy.show() self.next_melody = True self.playable.stop() # self.eHP.setValue(100) self.book.setStyleSheet('QLabel {color: Red }') self.the_right_answer = [False, False, True] self.write_in_battle('Усиленная атака сверху') time.sleep(2) if self.result is not True: self.write_in_battle('Вы погибли') time.sleep(2) self.close() else: self.eHP_points -= 10 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Вы успешно уклонились') self.result = False self.the_right_answer = [False, True, False] self.write_in_battle('Противник потерял равновесие') time.sleep(2) if self.result is not True: self.write_in_battle('Вы погибли') time.sleep(2) self.close() else: self.eHP_points -= 10 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Вы успешно атаковали') self.result = False self.the_right_answer = [False, False, True] self.write_in_battle('Выпад вперед!') time.sleep(1) if self.result is not True: self.write_in_battle('Вы погибли') time.sleep(2) self.close() else: self.eHP_points -= 10 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Ваш противник в ярости!') self.result = False self.the_right_answer = [True, False, False] self.write_in_battle('Полый нансосит слабый удар') time.sleep(1.5) if self.result is not True: self.write_in_battle('Вы погибли') time.sleep(2) self.close() else: self.eHP_points -= 10 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Щит сломан') self.result = False self.the_right_answer = [False, True, False] self.write_in_battle('Полый выронил меч. Это ваш шанс!') victory = False time.sleep(0.8) if self.result is not True: self.write_in_battle('Полый увернулся') self.write_in_battle('Вы подбираете его щит') else: self.eHP_points -= 60 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Полый побежден!') self.result = False victory = True if victory is False: self.the_right_answer = [False, False, True] self.write_in_battle('Полый нансосит слабый удар') time.sleep(1.5) if self.result is not True: self.write_in_battle('Вы погибли') time.sleep(2) self.close() else: self.eHP_points -= 30 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Парирование') self.result = False self.the_right_answer = [False, True, False] self.write_in_battle('Полый медленно замахнулся') time.sleep(1.5) if self.result is not True: self.write_in_battle('Вы погибли') time.sleep(2) self.close() else: self.eHP_points -= 30 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Полый сделал шаг назад') self.result = False self.the_right_answer = [False, True, False] self.write_in_battle('Полый поднимает меч') time.sleep(1.5) if self.result is not True: self.write_in_battle('Вы погибли') time.sleep(2) self.close() else: self.eHP_points -= 10 self.eHP.close() self.eHP.setValue(self.eHP_points) self.eHP.show() self.write_in_battle('Полый падает') self.result = False self.next_melody = False self.NPC_enemy.close() self.NPC_enemy.setStyleSheet( "QLabel {color: rgb(0, 0, 51);" 'background-color: rgba(10, 20, 100, 0.2);' 'border-color: rgba(100, 100, 100, 0.5);' 'border-style: solid;' 'border-width: 2px;' '}' 'QLabel:hover {background-color: rgba(100, 0, 0, 0.7)}') time.sleep(0.3) self.NPC_enemy.show() self.write('Полый побежден') if victory is True: self.NPC_enemy.close() self.NPC_enemy.setStyleSheet( 'QLabel { background-image: url(letter.jpg)}') time.sleep(0.3) self.NPC_enemy.show() self.write('Вы получили новый щит: урон противников снижен') self.write('Ваш щит сломан: урон противников повышен') self.write('Вы продолжаете идти по тропе') self.write('Справа от вас труп') self.write('В его карамане что-то есть') self.write('Найдена записка') self.write('С тех времен, как Гвин впервые ') self.write( 'разжег <не разобрать>, минуло много веков и много циклов <не разобрать>' ) self.write('пламени. После того, как он разжег огонь,') self.write('этот путь повторили многие великие герои, ') self.write('известные как <не разобрать>') def always_on(self): while True: time.sleep(0.5) if self.playable.isFinished() is True: if self.next_melody is False: self.playable2.stop() self.playable.play() if self.playable2.isFinished() is True: if self.next_melody is True: self.playable2.play() def change_size(self, input_image_path, size=(0, 0)): original_image = Image.open(input_image_path) resized_image = original_image.resize(size) resized_image.save(input_image_path) self.changed = True def write(self, text): your_text = ' ' for letter in text: if self.read is True: time.sleep(0.1) your_text += letter self.book.setText(your_text) else: self.read = True break time.sleep(0.2) def write_in_battle(self, text): your_text = ' ' for letter in text: time.sleep(0.05) your_text += letter self.book.setText(your_text) def defend_fnc(self): if self.the_right_answer[0] is True: self.result = True else: self.result = False self.action_targ.close() self.action_targ.move(self.targ_pos[1][0], self.targ_pos[1][1]) self.action_targ.show() def attack_fnc(self): if self.the_right_answer[1] is True: self.result = True else: self.result = False self.action_targ.close() self.action_targ.move(self.targ_pos[0][0], self.targ_pos[0][1]) self.action_targ.show() def dodge_fnc(self): if self.the_right_answer[2] is True: self.result = True else: self.result = False self.action_targ.close() self.action_targ.move(self.targ_pos[2][0], self.targ_pos[2][1]) self.action_targ.show()
class SystemTrayIcon(QMainWindow): def __init__(self, parent=None): super(SystemTrayIcon, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.settings = QSettings() self.language = self.settings.value('Language') or '' self.temp_decimal_bool = self.settings.value('Decimal') or False # initialize the tray icon type in case of first run: issue#42 self.tray_type = self.settings.value('TrayType') or 'icon&temp' cond = conditions.WeatherConditions() self.temporary_city_status = False self.conditions = cond.trans self.clouds = cond.clouds self.wind = cond.wind self.wind_dir = cond.wind_direction self.wind_codes = cond.wind_codes self.inerror = False self.tentatives = 0 self.baseurl = 'http://api.openweathermap.org/data/2.5/weather?id=' self.accurate_url = 'http://api.openweathermap.org/data/2.5/find?q=' self.forecast_url = ('http://api.openweathermap.org/data/2.5/forecast/' 'daily?id=') self.day_forecast_url = ('http://api.openweathermap.org/data/2.5/' 'forecast?id=') self.wIconUrl = 'http://openweathermap.org/img/w/' apikey = self.settings.value('APPID') or '' self.appid = '&APPID=' + apikey self.forecast_icon_url = self.wIconUrl self.timer = QTimer(self) self.timer.timeout.connect(self.refresh) self.menu = QMenu() self.citiesMenu = QMenu(self.tr('Cities')) self.panelAction = QAction( QCoreApplication.translate("Tray context menu", "Toggle Panel", "Menu entry"), self) self.tempCityAction = QAction(self.tr('&Temporary city'), self) self.refreshAction = QAction(self.tr('&Update'), self) self.settingsAction = QAction(self.tr('&Settings'), self) self.aboutAction = QAction(self.tr('&About'), self) self.exitAction = QAction(self.tr('Exit'), self) self.panelAction.setIcon(QIcon(':/panel')) self.exitAction.setIcon(QIcon(':/exit')) self.aboutAction.setIcon(QIcon(':/info')) self.refreshAction.setIcon(QIcon(':/refresh')) self.settingsAction.setIcon(QIcon(':/configure')) self.tempCityAction.setIcon(QIcon(':/tempcity')) self.citiesMenu.setIcon(QIcon(':/bookmarks')) self.menu.addAction(self.panelAction) self.menu.addAction(self.settingsAction) self.menu.addAction(self.refreshAction) self.menu.addMenu(self.citiesMenu) self.menu.addAction(self.tempCityAction) self.menu.addAction(self.aboutAction) self.menu.addAction(self.exitAction) self.panelAction.triggered.connect(self.showpanel) self.settingsAction.triggered.connect(self.config) self.exitAction.triggered.connect(qApp.quit) self.refreshAction.triggered.connect(self.manual_refresh) self.aboutAction.triggered.connect(self.about) self.tempCityAction.triggered.connect(self.tempcity) self.systray = QSystemTrayIcon() self.systray.setContextMenu(self.menu) self.systray.activated.connect(self.activate) self.systray.setIcon(QIcon(':/noicon')) self.systray.setToolTip(self.tr('Searching weather data...')) self.notification = '' self.notification_temp = 0 self.notifications_id = '' self.systray.show() # The dictionnary has to be intialized here. If there is an error # the program couldn't become functionnal if the dictionnary is # reinitialized in the weatherdata method self.weatherDataDico = {} # The traycolor has to be initialized here for the case when we cannot # reach the tray method (case: set the color at first time usage) self.traycolor = '' self.refresh() def icon_loading(self): self.gif_loading = QMovie(":/loading") self.gif_loading.frameChanged.connect(self.update_gif) self.gif_loading.start() def update_gif(self): gif_frame = self.gif_loading.currentPixmap() self.systray.setIcon(QIcon(gif_frame)) def manual_refresh(self): self.tentatives = 0 self.refresh() def cities_menu(self): # Don't add the temporary city in the list if self.temporary_city_status: return self.citiesMenu.clear() cities = self.settings.value('CityList') or [] if type(cities) is str: cities = eval(cities) try: current_city = (self.settings.value('City') + '_' + self.settings.value('Country') + '_' + self.settings.value('ID')) except: # firsttime run,if clic cancel in setings without any city configured pass # Prevent duplicate entries try: city_toadd = cities.pop(cities.index(current_city)) except: city_toadd = current_city finally: cities.insert(0, city_toadd) # If we delete all cities it results to a '__' if (cities is not None and cities != '' and cities != '[]' and cities != ['__']): if type(cities) is not list: # FIXME sometimes the list of cities is read as a string (?) # eval to a list cities = eval(cities) # Create the cities list menu for city in cities: action = QAction(city, self) action.triggered.connect(partial(self.changecity, city)) self.citiesMenu.addAction(action) else: self.empty_cities_list() @pyqtSlot(str) def changecity(self, city): cities_list = self.settings.value('CityList') logging.debug('Cities' + str(cities_list)) if cities_list is None: self.empty_cities_list() if type(cities_list) is not list: # FIXME some times is read as string (?) cities_list = eval(cities_list) prev_city = (self.settings.value('City') + '_' + self.settings.value('Country') + '_' + self.settings.value('ID')) citytoset = '' # Set the chosen city as the default for town in cities_list: if town == city: ind = cities_list.index(town) citytoset = cities_list[ind] citytosetlist = citytoset.split('_') self.settings.setValue('City', citytosetlist[0]) self.settings.setValue('Country', citytosetlist[1]) self.settings.setValue('ID', citytosetlist[2]) if prev_city not in cities_list: cities_list.append(prev_city) self.settings.setValue('CityList', cities_list) logging.debug(cities_list) self.refresh() def empty_cities_list(self): self.citiesMenu.addAction(self.tr('Empty list')) def refresh(self): self.inerror = False self.window_visible = False self.systray.setIcon(QIcon(':/noicon')) if hasattr(self, 'overviewcity'): # if visible, it has to ...remain visible # (try reason) Prevent C++ wrapper error try: if not self.overviewcity.isVisible(): # kills the reference to overviewcity # in order to be refreshed self.overviewcity.close() del self.overviewcity else: self.overviewcity.close() self.window_visible = True except: pass self.systray.setToolTip(self.tr('Fetching weather data ...')) self.city = self.settings.value('City') or '' self.id_ = self.settings.value('ID') or None if self.id_ is None: # Clear the menu, no cities configured self.citiesMenu.clear() self.empty_cities_list() # Sometimes self.overviewcity is in namespace but deleted try: self.overviewcity.close() except: e = sys.exc_info()[0] logging.error('Error closing overviewcity: ' + str(e)) pass self.timer.singleShot(2000, self.firsttime) self.id_ = '' self.systray.setToolTip(self.tr('No city configured')) return # A city has been found, create the cities menu now self.cities_menu() self.country = self.settings.value('Country') or '' self.unit = self.settings.value('Unit') or 'metric' self.suffix = ('&mode=xml&units=' + self.unit + self.appid) self.interval = int(self.settings.value('Interval') or 30) * 60 * 1000 self.timer.start(self.interval) self.update() def firsttime(self): self.temp = '' self.wIcon = QPixmap(':/noicon') self.systray.showMessage( 'meteo-qt:\n', self.tr('No city has been configured yet.') + '\n' + self.tr('Right click on the icon and click on Settings.')) def update(self): if hasattr(self, 'downloadThread'): if self.downloadThread.isRunning(): logging.debug('remaining thread...') return logging.debug('Update...') self.icon_loading() self.wIcon = QPixmap(':/noicon') self.downloadThread = Download(self.wIconUrl, self.baseurl, self.forecast_url, self.day_forecast_url, self.id_, self.suffix) self.downloadThread.wimage['PyQt_PyObject'].connect(self.makeicon) self.downloadThread.finished.connect(self.tray) self.downloadThread.xmlpage['PyQt_PyObject'].connect(self.weatherdata) self.downloadThread.forecast_rawpage.connect(self.forecast) self.downloadThread.day_forecast_rawpage.connect(self.dayforecast) self.downloadThread.uv_signal.connect(self.uv) self.downloadThread.error.connect(self.error) self.downloadThread.done.connect(self.done, Qt.QueuedConnection) self.downloadThread.start() def uv(self, value): self.uv_coord = value def forecast(self, data): self.forecast_data = data def dayforecast(self, data): if type(data) == dict: self.json_data_bool = True else: self.json_data_bool = False self.dayforecast_data = data def instance_overviewcity(self): try: self.inerror = False if hasattr(self, 'overviewcity'): logging.debug('Deleting overviewcity instance...') del self.overviewcity self.overviewcity = overview.OverviewCity( self.weatherDataDico, self.wIcon, self.forecast_data, self.dayforecast_data, self.json_data_bool, self.unit, self.forecast_icon_url, self.uv_coord, self) self.overviewcity.closed_status_dialogue.connect( self.remove_object) except: self.inerror = True e = sys.exc_info()[0] logging.error('Error: ' + str(e)) logging.debug('Try to create the city overview...\nAttempts: ' + str(self.tentatives)) return 'error' def remove_object(self): del self.overviewcity def done(self, done): if done == 0: self.inerror = False elif done == 1: self.inerror = True logging.debug('Trying to retrieve data ...') self.timer.singleShot(10000, self.try_again) return if hasattr(self, 'updateicon'): # Keep a reference of the image to update the icon in overview self.wIcon = self.updateicon if hasattr(self, 'forecast_data'): if hasattr(self, 'overviewcity'): try: # Update also the overview dialog if open if self.overviewcity.isVisible(): # delete dialog to prevent memory leak self.overviewcity.close() self.instance_overviewcity() self.overview() except: # if the dialogue has been closed by the 'X' button # remove the delelted window object from memory # RuntimeError: wrapped C/C++ object of type OverviewCity has been deleted self.remove_object() self.instance_overviewcity() elif self.window_visible is True: self.instance_overviewcity() self.overview() else: self.inerror = True self.try_create_overview() else: self.try_again() def try_create_overview(self): logging.debug('Tries to create overview :' + str(self.tentatives)) instance = self.instance_overviewcity() if instance == 'error': self.inerror = True self.refresh() else: self.tentatives = 0 self.inerror = False self.tooltip_weather() def try_again(self): self.nodata_message() logging.debug('Attempts: ' + str(self.tentatives)) self.tentatives += 1 self.timer.singleShot(5000, self.refresh) def nodata_message(self): nodata = QCoreApplication.translate( "Tray icon", "Searching for weather data...", "Tooltip (when mouse over the icon") self.systray.setToolTip(nodata) self.notification = nodata def error(self, error): logging.error('Error:\n' + str(error)) self.nodata_message() self.timer.start(self.interval) self.inerror = True def makeicon(self, data): image = QImage() image.loadFromData(data) self.wIcon = QPixmap(image) # Keep a reference of the image to update the icon in overview self.updateicon = self.wIcon def weatherdata(self, tree): if self.inerror: return self.tempFloat = tree[1].get('value') self.temp = ' ' + str(round(float(self.tempFloat))) + '°' self.temp_decimal = '{0:.1f}'.format(float(self.tempFloat)) + '°' self.meteo = tree[8].get('value') meteo_condition = tree[8].get('number') try: self.meteo = self.conditions[meteo_condition] except: logging.debug('Cannot find localisation string for' 'meteo_condition:' + str(meteo_condition)) pass clouds = tree[5].get('name') clouds_percent = tree[5].get('value') + '%' try: clouds = self.clouds[clouds] clouds = self.conditions[clouds] except: logging.debug('Cannot find localisation string for clouds:' + str(clouds)) pass wind = tree[4][0].get('name').lower() try: wind = self.wind[wind] wind = self.conditions[wind] except: logging.debug('Cannot find localisation string for wind:' + str(wind)) pass try: wind_codes = tree[4][2].get('code') wind_dir_value = tree[4][2].get('value') wind_dir = tree[4][2].get('name') except: wind_codes = tree[4][1].get('code') wind_dir_value = tree[4][1].get('value') wind_dir = tree[4][1].get('name') try: wind_codes = self.wind_codes[wind_codes] except: logging.debug('Cannot find localisation string for wind_codes:' + str(wind_codes)) pass try: wind_dir = self.wind_dir[tree[4][2].get('code')] except: logging.debug('Cannot find localisation string for wind_dir:' + str(wind_dir)) pass self.city_weather_info = (self.city + ' ' + self.country + ' ' + self.temp_decimal + ' ' + self.meteo) self.tooltip_weather() self.notification = self.city_weather_info self.weatherDataDico['City'] = self.city self.weatherDataDico['Country'] = self.country self.weatherDataDico['Temp'] = self.tempFloat + '°' self.weatherDataDico['Meteo'] = self.meteo self.weatherDataDico['Humidity'] = (tree[2].get('value'), tree[2].get('unit')) self.weatherDataDico['Wind'] = (tree[4][0].get('value'), wind, str(int(float(wind_dir_value))), wind_codes, wind_dir) self.weatherDataDico['Clouds'] = (clouds_percent + ' ' + clouds) self.weatherDataDico['Pressure'] = (tree[3].get('value'), tree[3].get('unit')) self.weatherDataDico['Humidity'] = (tree[2].get('value'), tree[2].get('unit')) self.weatherDataDico['Sunrise'] = tree[0][2].get('rise') self.weatherDataDico['Sunset'] = tree[0][2].get('set') rain_value = tree[7].get('value') if rain_value == None: rain_value = '' self.weatherDataDico['Precipitation'] = (tree[7].get('mode'), rain_value) def tooltip_weather(self): self.systray.setToolTip(self.city_weather_info) def tray(self): temp_decimal = eval(self.settings.value('Decimal') or 'False') try: if temp_decimal: temp_tray = self.temp_decimal else: temp_tray = self.temp except: # First time launch return if self.inerror or not hasattr(self, 'temp'): logging.critical('Cannot paint icon!') if hasattr(self, 'overviewcity'): try: # delete dialog to prevent memory leak self.overviewcity.close() except: pass return try: self.gif_loading.stop() except: # In first time run the gif is not animated pass logging.debug('Paint tray icon...') # Place empty.png here to initialize the icon # don't paint the T° over the old value icon = QPixmap(':/empty') self.traycolor = self.settings.value('TrayColor') or '' self.fontsize = self.settings.value('FontSize') or '18' self.tray_type = self.settings.value('TrayType') or 'icon&temp' pt = QPainter() pt.begin(icon) if self.tray_type != 'temp': pt.drawPixmap(0, -12, 64, 64, self.wIcon) pt.setFont(QFont('sans-sertif', int(self.fontsize))) pt.setPen(QColor(self.traycolor)) if self.tray_type == 'icon&temp': pt.drawText(icon.rect(), Qt.AlignBottom | Qt.AlignCenter, str(temp_tray)) if self.tray_type == 'temp': pt.drawText(icon.rect(), Qt.AlignCenter, str(temp_tray)) pt.end() if self.tray_type == 'icon': self.systray.setIcon(QIcon(self.wIcon)) else: self.systray.setIcon(QIcon(icon)) try: if not self.overviewcity.isVisible(): notifier = self.settings.value('Notifications') or 'True' notifier = eval(notifier) if notifier: temp = int(re.search('\d+', self.temp_decimal).group()) if temp != self.notification_temp or self.id_ != self.notifications_id: self.notifications_id = self.id_ self.notification_temp = temp self.systray.showMessage('meteo-qt', self.notification) except: logging.debug('OverviewCity has been deleted' + 'Download weather information again...') self.try_again() return self.restore_city() self.tentatives = 0 self.tooltip_weather() logging.info('Actual weather status for: ' + self.notification) def restore_city(self): if self.temporary_city_status: logging.debug('Restore the default settings (city)' + 'Forget the temporary city...') for e in ('ID', self.id_2), ('City', self.city2), ('Country', self.country2): self.citydata(e) self.temporary_city_status = False def showpanel(self): self.activate(3) def activate(self, reason): if reason == 3: if self.inerror or self.id_ is None or self.id_ == '': return try: if hasattr(self, 'overviewcity') and self.overviewcity.isVisible(): self.overviewcity.hide() else: self.overviewcity.hide() # If dialog closed by the "X" self.done(0) self.overview() except: self.done(0) self.overview() elif reason == 1: self.menu.popup(QCursor.pos()) def overview(self): if self.inerror or len(self.weatherDataDico) == 0: return self.overviewcity.show() def config_save(self): logging.debug('Config saving...') city = self.settings.value('City'), id_ = self.settings.value('ID') country = self.settings.value('Country') unit = self.settings.value('Unit') traycolor = self.settings.value('TrayColor') tray_type = self.settings.value('TrayType') fontsize = self.settings.value('FontSize') language = self.settings.value('Language') decimal = self.settings.value('Decimal') self.appid = '&APPID=' + self.settings.value('APPID') or '' if language != self.language and language is not None: self.systray.showMessage( 'meteo-qt:', QCoreApplication.translate( "System tray notification", "The application has to be restarted to apply the language setting", '')) self.language = language # Check if update is needed if traycolor is None: traycolor = '' if (self.traycolor != traycolor or self.tray_type != tray_type or self.fontsize != fontsize or decimal != self.temp_decimal): self.tray() if (city[0] == self.city and id_ == self.id_ and country == self.country and unit == self.unit): return else: logging.debug('Apply changes from settings...') self.refresh() def config(self): dialog = settings.MeteoSettings(self.accurate_url, self.appid, self) dialog.applied_signal.connect(self.config_save) if dialog.exec_() == 1: self.config_save() logging.debug('Update Cities menu...') self.cities_menu() def tempcity(self): # Prevent to register a temporary city # This happen when a temporary city is still loading self.restore_city() dialog = searchcity.SearchCity(self.accurate_url, self.appid, self) self.id_2, self.city2, self.country2 = (self.settings.value('ID'), self.settings.value('City'), self.settings.value('Country')) dialog.id_signal[tuple].connect(self.citydata) dialog.city_signal[tuple].connect(self.citydata) dialog.country_signal[tuple].connect(self.citydata) if dialog.exec_(): self.temporary_city_status = True self.systray.setToolTip(self.tr('Fetching weather data...')) self.refresh() def citydata(self, what): self.settings.setValue(what[0], what[1]) logging.debug('write ' + str(what[0]) + ' ' + str(what[1])) def about(self): title = self.tr("""<b>meteo-qt</b> v{0} <br/>License: GPLv3 <br/>Python {1} - Qt {2} - PyQt {3} on {4}""").format( __version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) image = ':/logo' text = self.tr( """<p>Author: Dimitrios Glentadakis <a href="mailto:[email protected]">[email protected]</a> <p>A simple application showing the weather status information on the system tray. <p>Website: <a href="https://github.com/dglent/meteo-qt"> https://github.com/dglent/meteo-qt</a> <br/>Data source: <a href="http://openweathermap.org/"> OpenWeatherMap</a>. <br/>This software uses icons from the <a href="http://www.kde.org/">Oxygen Project</a>. <p>To translate meteo-qt in your language or contribute to current translations, you can use the <a href="https://www.transifex.com/projects/p/meteo-qt/"> Transifex</a> platform. <p>If you want to report a dysfunction or a suggestion, feel free to open an issue in <a href="https://github.com/dglent/meteo-qt/issues"> github</a>.""") contributors = QCoreApplication.translate( "About dialog", """ Pavel Fric<br/> [cs] Czech translation <p>Jürgen <a href="mailto:[email protected]">[email protected]</a><br/> [de] German translation <p>Peter Mattern <a href="mailto:[email protected]">[email protected]</a><br/> [de] German translation, Project <p>Dimitrios Glentadakis <a href="mailto:[email protected]">[email protected]</a><br/> [el] Greek translation <p> juancarlospaco <a href="mailto:[email protected]">[email protected]</a><br/> [es] Spanish translation, Project <p>Ozkar L. Garcell <a href="mailto:[email protected]">[email protected]</a><br/> [es] Spanish translation <p>Laurene Albrand <a href="mailto:[email protected]">[email protected]</a><br/> [fr] French translation <p>Rémi Verschelde <a href="mailto:[email protected]">[email protected]</a><br/> [fr] French translation, Project <p>Daniel Napora <a href="mailto:[email protected]">[email protected]</a><br/> Tomasz Przybył <a href="mailto:[email protected]">[email protected]</a><br/> [pl] Polish translation <p>Artem Vorotnikov <a href="mailto:[email protected]">[email protected]</a><br/> [ru] Russian translation <p>Atilla Öntaş <a href="mailto:[email protected]">[email protected]</a><br/> [tr] Turkish translation <p>Yuri Chornoivan <a href="mailto:[email protected]">[email protected]</a><br/> [uk] Ukrainian translation <p>You-Cheng Hsieh <a href="mailto:[email protected]">[email protected]</a><br/> [zh_TW] Chinese (Taiwan) translation <p>pmav99<br/> Project""", "List of contributors") dialog = about_dlg.AboutDialog(title, text, image, contributors, self) dialog.exec_()
class SystemTrayIcon(QMainWindow): def __init__(self, parent=None): super(SystemTrayIcon, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.settings = QSettings() self.language = self.settings.value('Language') or '' self.temp_decimal_bool = self.settings.value('Decimal') or False # initialize the tray icon type in case of first run: issue#42 self.tray_type = self.settings.value('TrayType') or 'icon&temp' cond = conditions.WeatherConditions() self.temporary_city_status = False self.conditions = cond.trans self.clouds = cond.clouds self.wind = cond.wind self.wind_dir = cond.wind_direction self.wind_codes = cond.wind_codes self.inerror = False self.tentatives = 0 self.baseurl = 'http://api.openweathermap.org/data/2.5/weather?id=' self.accurate_url = 'http://api.openweathermap.org/data/2.5/find?q=' self.forecast_url = ('http://api.openweathermap.org/data/2.5/forecast/' 'daily?id=') self.day_forecast_url = ('http://api.openweathermap.org/data/2.5/' 'forecast?id=') self.wIconUrl = 'http://openweathermap.org/img/w/' apikey = self.settings.value('APPID') or '' self.appid = '&APPID=' + apikey self.forecast_icon_url = self.wIconUrl self.timer = QTimer(self) self.timer.timeout.connect(self.refresh) self.menu = QMenu() self.citiesMenu = QMenu(self.tr('Cities')) self.tempCityAction = QAction(self.tr('&Temporary city'), self) self.refreshAction = QAction(self.tr('&Update'), self) self.settingsAction = QAction(self.tr('&Settings'), self) self.aboutAction = QAction(self.tr('&About'), self) self.exitAction = QAction(self.tr('Exit'), self) self.exitAction.setIcon(QIcon(':/exit')) self.aboutAction.setIcon(QIcon(':/info')) self.refreshAction.setIcon(QIcon(':/refresh')) self.settingsAction.setIcon(QIcon(':/configure')) self.tempCityAction.setIcon(QIcon(':/tempcity')) self.citiesMenu.setIcon(QIcon(':/bookmarks')) self.menu.addAction(self.settingsAction) self.menu.addAction(self.refreshAction) self.menu.addMenu(self.citiesMenu) self.menu.addAction(self.tempCityAction) self.menu.addAction(self.aboutAction) self.menu.addAction(self.exitAction) self.settingsAction.triggered.connect(self.config) self.exitAction.triggered.connect(qApp.quit) self.refreshAction.triggered.connect(self.manual_refresh) self.aboutAction.triggered.connect(self.about) self.tempCityAction.triggered.connect(self.tempcity) self.systray = QSystemTrayIcon() self.systray.setContextMenu(self.menu) self.systray.activated.connect(self.activate) self.systray.setIcon(QIcon(':/noicon')) self.systray.setToolTip(self.tr('Searching weather data...')) self.notification = '' self.notification_temp = 0 self.notifications_id = '' self.systray.show() # The dictionnary has to be intialized here. If there is an error # the program couldn't become functionnal if the dictionnary is # reinitialized in the weatherdata method self.weatherDataDico = {} # The traycolor has to be initialized here for the case when we cannot # reach the tray method (case: set the color at first time usage) self.traycolor = '' self.refresh() def icon_loading(self): self.gif_loading = QMovie(":/loading") self.gif_loading.frameChanged.connect(self.update_gif) self.gif_loading.start() def update_gif(self): gif_frame = self.gif_loading.currentPixmap() self.systray.setIcon(QIcon(gif_frame)) def manual_refresh(self): self.tentatives = 0 self.refresh() def cities_menu(self): # Don't add the temporary city in the list if self.temporary_city_status: return self.citiesMenu.clear() cities = self.settings.value('CityList') or [] if type(cities) is str: cities = eval(cities) try: current_city = (self.settings.value('City') + '_' + self.settings.value('Country') + '_' + self.settings.value('ID')) except: # firsttime run,if clic cancel in setings without any city configured pass # Prevent duplicate entries try: city_toadd = cities.pop(cities.index(current_city)) except: city_toadd = current_city finally: cities.insert(0, city_toadd) # If we delete all cities it results to a '__' if (cities is not None and cities != '' and cities != '[]' and cities != ['__']): if type(cities) is not list: # FIXME sometimes the list of cities is read as a string (?) # eval to a list cities = eval(cities) # Create the cities list menu for city in cities: action = QAction(city, self) action.triggered.connect(partial(self.changecity, city)) self.citiesMenu.addAction(action) else: self.empty_cities_list() @pyqtSlot(str) def changecity(self, city): cities_list = self.settings.value('CityList') logging.debug('Cities' + str(cities_list)) if cities_list is None: self.empty_cities_list() if type(cities_list) is not list: # FIXME some times is read as string (?) cities_list = eval(cities_list) prev_city = (self.settings.value('City') + '_' + self.settings.value('Country') + '_' + self.settings.value('ID')) citytoset = '' # Set the chosen city as the default for town in cities_list: if town == city: ind = cities_list.index(town) citytoset = cities_list[ind] citytosetlist = citytoset.split('_') self.settings.setValue('City', citytosetlist[0]) self.settings.setValue('Country', citytosetlist[1]) self.settings.setValue('ID', citytosetlist[2]) if prev_city not in cities_list: cities_list.append(prev_city) self.settings.setValue('CityList', cities_list) logging.debug(cities_list) self.refresh() def empty_cities_list(self): self.citiesMenu.addAction(self.tr('Empty list')) def refresh(self): self.inerror = False self.window_visible = False self.systray.setIcon(QIcon(':/noicon')) if hasattr(self, 'overviewcity'): # if visible, it has to ...remain visible # (try reason) Prevent C++ wrapper error try: if not self.overviewcity.isVisible(): # kills the reference to overviewcity # in order to be refreshed self.overviewcity.close() del self.overviewcity else: self.overviewcity.close() self.window_visible = True except: pass self.systray.setToolTip(self.tr('Fetching weather data ...')) self.city = self.settings.value('City') or '' self.id_ = self.settings.value('ID') or None if self.id_ is None: # Clear the menu, no cities configured self.citiesMenu.clear() self.empty_cities_list() # Sometimes self.overviewcity is in namespace but deleted try: self.overviewcity.close() except: e = sys.exc_info()[0] logging.error('Error closing overviewcity: ' + str(e)) pass self.timer.singleShot(2000, self.firsttime) self.id_ = '' self.systray.setToolTip(self.tr('No city configured')) return # A city has been found, create the cities menu now self.cities_menu() self.country = self.settings.value('Country') or '' self.unit = self.settings.value('Unit') or 'metric' self.suffix = ('&mode=xml&units=' + self.unit + self.appid) self.interval = int(self.settings.value('Interval') or 30)*60*1000 self.timer.start(self.interval) self.update() def firsttime(self): self.temp = '' self.wIcon = QPixmap(':/noicon') self.systray.showMessage( 'meteo-qt:\n', self.tr('No city has been configured yet.') + '\n' + self.tr('Right click on the icon and click on Settings.')) def update(self): if hasattr(self, 'downloadThread'): if self.downloadThread.isRunning(): logging.debug('remaining thread...') return logging.debug('Update...') self.icon_loading() self.wIcon = QPixmap(':/noicon') self.downloadThread = Download( self.wIconUrl, self.baseurl, self.forecast_url, self.day_forecast_url, self.id_, self.suffix) self.downloadThread.wimage['PyQt_PyObject'].connect(self.makeicon) self.downloadThread.finished.connect(self.tray) self.downloadThread.xmlpage['PyQt_PyObject'].connect(self.weatherdata) self.downloadThread.forecast_rawpage.connect(self.forecast) self.downloadThread.day_forecast_rawpage.connect(self.dayforecast) self.downloadThread.uv_signal.connect(self.uv) self.downloadThread.error.connect(self.error) self.downloadThread.done.connect(self.done, Qt.QueuedConnection) self.downloadThread.start() def uv(self, value): self.uv_coord = value def forecast(self, data): self.forecast_data = data def dayforecast(self, data): self.dayforecast_data = data def instance_overviewcity(self): try: self.inerror = False if hasattr(self, 'overviewcity'): logging.debug('Deleting overviewcity instance...') del self.overviewcity self.overviewcity = overview.OverviewCity( self.weatherDataDico, self.wIcon, self.forecast_data, self.dayforecast_data, self.unit, self.forecast_icon_url, self.uv_coord, self) self.overviewcity.closed_status_dialogue.connect(self.remove_object) except: self.inerror = True e = sys.exc_info()[0] logging.error('Error: ' + str(e)) logging.debug('Try to create the city overview...\nAttempts: ' + str(self.tentatives)) return 'error' def remove_object(self): del self.overviewcity def done(self, done): if done == 0: self.inerror = False elif done == 1: self.inerror = True logging.debug('Trying to retrieve data ...') self.timer.singleShot(10000, self.try_again) return if hasattr(self, 'updateicon'): # Keep a reference of the image to update the icon in overview self.wIcon = self.updateicon if hasattr(self, 'forecast_data'): if hasattr(self, 'overviewcity'): # Update also the overview dialog if open if self.overviewcity.isVisible(): # delete dialog to prevent memory leak self.overviewcity.close() self.instance_overviewcity() self.overview() elif self.window_visible is True: self.instance_overviewcity() self.overview() else: self.inerror = True self.try_create_overview() else: self.try_again() def try_create_overview(self): logging.debug('Tries to create overview :' + str(self.tentatives)) instance = self.instance_overviewcity() if instance == 'error': self.inerror = True self.refresh() else: self.tentatives = 0 self.inerror = False self.tooltip_weather() def try_again(self): self.nodata_message() logging.debug('Attempts: ' + str(self.tentatives)) self.tentatives += 1 self.timer.singleShot(5000, self.refresh) def nodata_message(self): nodata = QCoreApplication.translate( "Tray icon", "Searching for weather data...", "Tooltip (when mouse over the icon") self.systray.setToolTip(nodata) self.notification = nodata def error(self, error): logging.error('Error:\n' + str(error)) self.nodata_message() self.timer.start(self.interval) self.inerror = True def makeicon(self, data): image = QImage() image.loadFromData(data) self.wIcon = QPixmap(image) # Keep a reference of the image to update the icon in overview self.updateicon = self.wIcon def weatherdata(self, tree): if self.inerror: return self.tempFloat = tree[1].get('value') self.temp = ' ' + str(round(float(self.tempFloat))) + '°' self.temp_decimal = '{0:.1f}'.format(float(self.tempFloat)) + '°' self.meteo = tree[8].get('value') meteo_condition = tree[8].get('number') try: self.meteo = self.conditions[meteo_condition] except: logging.debug('Cannot find localisation string for' 'meteo_condition:' + str(meteo_condition)) pass clouds = tree[5].get('name') clouds_percent = tree[5].get('value') + '%' try: clouds = self.clouds[clouds] clouds = self.conditions[clouds] except: logging.debug('Cannot find localisation string for clouds:' + str(clouds)) pass wind = tree[4][0].get('name').lower() try: wind = self.wind[wind] wind = self.conditions[wind] except: logging.debug('Cannot find localisation string for wind:' + str(wind)) pass wind_codes = tree[4][2].get('code') try: wind_codes = self.wind_codes[wind_codes] except: logging.debug('Cannot find localisation string for wind_codes:' + str(wind_codes)) pass wind_dir = tree[4][2].get('name') try: wind_dir = self.wind_dir[tree[4][2].get('code')] except: logging.debug('Cannot find localisation string for wind_dir:' + str(wind_dir)) pass self.city_weather_info = (self.city + ' ' + self.country + ' ' + self.temp_decimal + ' ' + self.meteo) self.tooltip_weather() self.notification = self.city_weather_info self.weatherDataDico['City'] = self.city self.weatherDataDico['Country'] = self.country self.weatherDataDico['Temp'] = self.tempFloat + '°' self.weatherDataDico['Meteo'] = self.meteo self.weatherDataDico['Humidity'] = (tree[2].get('value'), tree[2].get('unit')) self.weatherDataDico['Wind'] = ( tree[4][0].get('value'), wind, str(int(float(tree[4][2].get('value')))), wind_codes, wind_dir) self.weatherDataDico['Clouds'] = (clouds_percent + ' ' + clouds) self.weatherDataDico['Pressure'] = (tree[3].get('value'), tree[3].get('unit')) self.weatherDataDico['Humidity'] = (tree[2].get('value'), tree[2].get('unit')) self.weatherDataDico['Sunrise'] = tree[0][2].get('rise') self.weatherDataDico['Sunset'] = tree[0][2].get('set') rain_value = tree[7].get('value') if rain_value == None: rain_value = '' self.weatherDataDico['Precipitation'] = (tree[7].get('mode'), rain_value) def tooltip_weather(self): self.systray.setToolTip(self.city_weather_info) def tray(self): temp_decimal = eval(self.settings.value('Decimal') or 'False') try: if temp_decimal: temp_tray = self.temp_decimal else: temp_tray = self.temp except: # First time launch return if self.inerror or not hasattr(self, 'temp'): logging.critical('Cannot paint icon!') if hasattr(self, 'overviewcity'): try: # delete dialog to prevent memory leak self.overviewcity.close() except: pass return try: self.gif_loading.stop() except: # In first time run the gif is not animated pass logging.debug('Paint tray icon...') # Place empty.png here to initialize the icon # don't paint the T° over the old value icon = QPixmap(':/empty') self.traycolor = self.settings.value('TrayColor') or '' self.fontsize = self.settings.value('FontSize') or '18' self.tray_type = self.settings.value('TrayType') or 'icon&temp' pt = QPainter() pt.begin(icon) if self.tray_type != 'temp': pt.drawPixmap(0, -12, 64, 64, self.wIcon) pt.setFont(QFont('sans-sertif', int(self.fontsize))) pt.setPen(QColor(self.traycolor)) if self.tray_type == 'icon&temp': pt.drawText(icon.rect(), Qt.AlignBottom | Qt.AlignCenter, str(temp_tray)) if self.tray_type == 'temp': pt.drawText(icon.rect(), Qt.AlignCenter, str(temp_tray)) pt.end() if self.tray_type == 'icon': self.systray.setIcon(QIcon(self.wIcon)) else: self.systray.setIcon(QIcon(icon)) try: if not self.overviewcity.isVisible(): notifier = self.settings.value('Notifications') or 'True' notifier = eval(notifier) if notifier: temp = int(re.search('\d+', self.temp_decimal).group()) if temp != self.notification_temp or self.id_ != self.notifications_id: self.notifications_id = self.id_ self.notification_temp = temp self.systray.showMessage('meteo-qt', self.notification) except: logging.debug('OverviewCity has been deleted' + 'Download weather information again...') self.try_again() return self.restore_city() self.tentatives = 0 self.tooltip_weather() logging.info('Actual weather status for: ' + self.notification) def restore_city(self): if self.temporary_city_status: logging.debug('Restore the default settings (city)' + 'Forget the temporary city...') for e in ('ID', self.id_2), ('City', self.city2), ('Country', self.country2): self.citydata(e) self.temporary_city_status = False def activate(self, reason): if reason == 3: if self.inerror or self.id_ is None or self.id_ == '': return try: if hasattr(self, 'overviewcity') and self.overviewcity.isVisible(): self.overviewcity.hide() else: self.overviewcity.hide() # If dialog closed by the "X" self.done(0) self.overview() except: self.done(0) self.overview() elif reason == 1: self.menu.popup(QCursor.pos()) def overview(self): if self.inerror or len(self.weatherDataDico) == 0: return self.overviewcity.show() def config_save(self): logging.debug('Config saving...') city = self.settings.value('City'), id_ = self.settings.value('ID') country = self.settings.value('Country') unit = self.settings.value('Unit') traycolor = self.settings.value('TrayColor') tray_type = self.settings.value('TrayType') fontsize = self.settings.value('FontSize') language = self.settings.value('Language') decimal = self.settings.value('Decimal') self.appid = '&APPID=' + self.settings.value('APPID') or '' if language != self.language and language is not None: self.systray.showMessage('meteo-qt:',QCoreApplication.translate( "System tray notification", "The application has to be restarted to apply the language setting", '')) self.language = language # Check if update is needed if traycolor is None: traycolor = '' if (self.traycolor != traycolor or self.tray_type != tray_type or self.fontsize != fontsize or decimal != self.temp_decimal): self.tray() if (city[0] == self.city and id_ == self.id_ and country == self.country and unit == self.unit): return else: logging.debug('Apply changes from settings...') self.refresh() def config(self): dialog = settings.MeteoSettings(self.accurate_url, self.appid, self) dialog.applied_signal.connect(self.config_save) if dialog.exec_() == 1: self.config_save() logging.debug('Update Cities menu...') self.cities_menu() def tempcity(self): # Prevent to register a temporary city # This happen when a temporary city is still loading self.restore_city() dialog = searchcity.SearchCity(self.accurate_url, self.appid, self) self.id_2, self.city2, self.country2 = (self.settings.value('ID'), self.settings.value('City'), self.settings.value('Country')) dialog.id_signal[tuple].connect(self.citydata) dialog.city_signal[tuple].connect(self.citydata) dialog.country_signal[tuple].connect(self.citydata) if dialog.exec_(): self.temporary_city_status = True self.systray.setToolTip(self.tr('Fetching weather data...')) self.refresh() def citydata(self, what): self.settings.setValue(what[0], what[1]) logging.debug('write ' + str(what[0]) + ' ' + str(what[1])) def about(self): title = self.tr("""<b>meteo-qt</b> v{0} <br/>License: GPLv3 <br/>Python {1} - Qt {2} - PyQt {3} on {4}""").format( __version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) image = ':/logo' text = self.tr("""<p>Author: Dimitrios Glentadakis <a href="mailto:[email protected]">[email protected]</a> <p>A simple application showing the weather status information on the system tray. <p>Website: <a href="https://github.com/dglent/meteo-qt"> https://github.com/dglent/meteo-qt</a> <br/>Data source: <a href="http://openweathermap.org/"> OpenWeatherMap</a>. <br/>This software uses icons from the <a href="http://www.kde.org/">Oxygen Project</a>. <p>To translate meteo-qt in your language or contribute to current translations, you can use the <a href="https://www.transifex.com/projects/p/meteo-qt/"> Transifex</a> platform. <p>If you want to report a dysfunction or a suggestion, feel free to open an issue in <a href="https://github.com/dglent/meteo-qt/issues"> github</a>.""") contributors = QCoreApplication.translate("About dialog", """ Pavel Fric<br/> [cs] Czech translation <p>Jürgen <a href="mailto:[email protected]">[email protected]</a><br/> [de] German translation <p>Peter Mattern <a href="mailto:[email protected]">[email protected]</a><br/> [de] German translation, Project <p>Dimitrios Glentadakis <a href="mailto:[email protected]">[email protected]</a><br/> [el] Greek translation <p>Ozkar L. Garcell <a href="mailto:[email protected]">[email protected]</a><br/> [es] Spanish translation <p>Laurene Albrand <a href="mailto:[email protected]">[email protected]</a><br/> [fr] French translation <p>Rémi Verschelde <a href="mailto:[email protected]">[email protected]</a><br/> [fr] French translation, Project <p>Daniel Napora <a href="mailto:[email protected]">[email protected]</a><br/> Tomasz Przybył <a href="mailto:[email protected]">[email protected]</a><br/> [pl] Polish translation <p>Artem Vorotnikov <a href="mailto:[email protected]">[email protected]</a><br/> [ru] Russian translation <p>Atilla Öntaş <a href="mailto:[email protected]">[email protected]</a><br/> [tr] Turkish translation <p>Yuri Chornoivan <a href="mailto:[email protected]">[email protected]</a><br/> [uk] Ukrainian translation <p>You-Cheng Hsieh <a href="mailto:[email protected]">[email protected]</a><br/> [zh_TW] Chinese (Taiwan) translation <p>pmav99<br/> Project""", "List of contributors") dialog = about_dlg.AboutDialog(title, text, image, contributors, self) dialog.exec_()
class StatusPanel(QWidget): def __init__(self, gateway, gui): super().__init__() self.gateway = gateway self.gui = gui self.state = 0 self.num_connected = 0 self.num_known = 0 self.available_space = 0 self.checkmark_icon = QLabel() self.checkmark_icon.setPixmap(Pixmap("checkmark.png", 20)) self.syncing_icon = QLabel() self.sync_movie = QMovie(resource("sync.gif")) self.sync_movie.setCacheMode(True) self.sync_movie.updated.connect( lambda: self.syncing_icon.setPixmap(self.sync_movie.currentPixmap( ).scaled(20, 20, Qt.KeepAspectRatio, Qt.SmoothTransformation))) self.status_label = QLabel() p = self.palette() dimmer_grey = BlendedColor(p.windowText().color(), p.window().color(), 0.6).name() self.status_label.setStyleSheet(f"QLabel {{ color: {dimmer_grey} }}") self.status_label.setFont(Font(10)) self.setStyleSheet("QToolButton { border: none }") # self.setStyleSheet(""" # QToolButton { color: dimgrey; border: none; } # QToolButton:hover { # background-color: #FAFAFA; # border: 1px solid grey; # border-radius: 2px; # } # """) self.tor_button = QToolButton() self.tor_button.setIconSize(QSize(20, 20)) self.tor_action = QAction( QIcon(resource("tor-onion.png")), "This connection is being routed through the Tor network", ) self.tor_button.setDefaultAction(self.tor_action) if not self.gateway.use_tor: self.tor_button.hide() preferences_button = QToolButton(self) preferences_button.setIcon(QIcon(resource("preferences.png"))) preferences_button.setIconSize(QSize(20, 20)) preferences_button.setMenu(Menu(self.gui, show_open_action=False)) preferences_button.setPopupMode(2) preferences_button.setStyleSheet( "QToolButton::menu-indicator { image: none }") layout = QGridLayout(self) left, _, right, bottom = layout.getContentsMargins() layout.setContentsMargins(left, 0, right, bottom - 2) layout.addWidget(self.checkmark_icon, 1, 1) layout.addWidget(self.syncing_icon, 1, 1) layout.addWidget(self.status_label, 1, 2) layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3) layout.addWidget(self.tor_button, 1, 4) layout.addWidget(preferences_button, 1, 6) self.gateway.monitor.total_sync_state_updated.connect( self.on_sync_state_updated) self.gateway.monitor.space_updated.connect(self.on_space_updated) self.gateway.monitor.nodes_updated.connect(self.on_nodes_updated) self.on_sync_state_updated(0) def _update_status_label(self): if self.state == 0: if self.gateway.shares_happy: if self.num_connected < self.gateway.shares_happy: self.status_label.setText( f"Connecting to {self.gateway.name} (" f"{self.num_connected}/{self.gateway.shares_happy})..." ) else: self.status_label.setText( f"Connected to {self.gateway.name}") else: self.status_label.setText( f"Connecting to {self.gateway.name}...") self.sync_movie.setPaused(True) self.syncing_icon.hide() self.checkmark_icon.hide() elif self.state == 1: self.status_label.setText("Syncing") self.checkmark_icon.hide() self.syncing_icon.show() self.sync_movie.setPaused(False) elif self.state == 2: self.status_label.setText("Up to date") self.sync_movie.setPaused(True) self.syncing_icon.hide() self.checkmark_icon.show() if self.available_space: self.status_label.setToolTip( "Connected to {} of {} storage nodes\n{} available".format( self.num_connected, self.num_known, self.available_space)) else: self.status_label.setToolTip( "Connected to {} of {} storage nodes".format( self.num_connected, self.num_known)) def on_sync_state_updated(self, state): self.state = state self._update_status_label() def on_space_updated(self, space): self.available_space = naturalsize(space) self._update_status_label() def on_nodes_updated(self, connected, known): self.num_connected = connected self.num_known = known self._update_status_label()
class QgsFmvPlayer(QMainWindow, Ui_PlayerWindow): """ Video Player Class """ def __init__(self, iface, path=None, parent=None): """ Constructor """ super(QgsFmvPlayer, self).__init__(parent) self.setupUi(self) self.parent = parent self.iface = iface self.fileName = None self.metadataDlg = None self.createingMosaic = False self.currentInfo = 0.0 self.RecGIF = QMovie(":/imgFMV/images/record.gif") self.videoWidget.customContextMenuRequested[QPoint].connect( self.contextMenuRequested) self.duration = 0 self.playerMuted = False self.HasFileAudio = False self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.player.setNotifyInterval(1000) # One second self.pass_time = 0.1 self.playlist = QMediaPlaylist() # self.player.setVideoOutput( # self.videoWidget) # Standar Surface self.player.setVideoOutput( self.videoWidget.videoSurface()) # Custom Surface self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.stateChanged.connect(self.setCurrentState) self.playerState = QMediaPlayer.StoppedState self.playFile(path) self.sliderDuration.setRange(0, self.player.duration() / 1000) self.volumeSlider.setValue(self.player.volume()) self.volumeSlider.enterEvent = self.showVolumeTip if self.metadataDlg is None: self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.setMinimumWidth(500) self.metadataDlg.hide() def HasMetadata(self, videoPath): """ Check if video have Metadata or not """ try: p = _spawn([ '-i', videoPath, '-map', 'data-re', '-codec', 'copy', '-f', 'data', '-' ]) stdout_data, _ = p.communicate() if stdout_data == b'': qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "This video don't have Metadata ! : "), level=QGis.Info) return False return True except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Metadata Callback Failed! : "), str(e), level=QGis.Info) def HasAudio(self, videoPath): """ Check if video have Metadata or not """ try: p = _spawn([ '-i', videoPath, '-show_streams', '-select_streams', 'a', '-loglevel', 'error' ], type="ffprobe") stdout_data, _ = p.communicate() if stdout_data == b'': qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "This video don't have Audio ! : "), level=QGis.Info) return False return True except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Audio check Failed! : "), str(e), level=QGis.Info) def callBackMetadata(self, currentTime, nextTime): """ Metadata CallBack """ try: # TODO : Speed this function # stdout_data = _check_output(['-i', self.fileName, # '-ss', currentTime, # '-to', nextTime, # '-f', 'data', '-']) t = callBackMetadataThread(cmds=[ '-i', self.fileName, '-ss', currentTime, '-to', nextTime, '-map', 'data-re', '-f', 'data', '-' ]) t.start() t.join(1) if t.is_alive(): t.p.terminate() t.join() if t.stdout == b'': return for packet in StreamParser(t.stdout): try: self.addMetadata(packet.MetadataList()) UpdateLayers(packet, parent=self, mosaic=self.createingMosaic) self.iface.mapCanvas().refresh() QApplication.processEvents() return except Exception as e: None except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Metadata Callback Failed! : "), str(e), level=QGis.Info) def addMetadata(self, packet): ''' Add Metadata to List ''' self.clearMetadata() row = 0 for key in sorted(packet.keys()): self.metadataDlg.VManager.insertRow(row) self.metadataDlg.VManager.setItem(row, 0, QTableWidgetItem(str(key))) self.metadataDlg.VManager.setItem( row, 1, QTableWidgetItem(str(packet[key][0]))) self.metadataDlg.VManager.setItem( row, 2, QTableWidgetItem(str(packet[key][1]))) row += 1 self.metadataDlg.VManager.setVisible(False) self.metadataDlg.VManager.resizeColumnsToContents() self.metadataDlg.VManager.setVisible(True) self.metadataDlg.VManager.verticalScrollBar().setSliderPosition( self.sliderPosition) def clearMetadata(self): ''' Clear Metadata List ''' try: self.sliderPosition = self.metadataDlg.VManager.verticalScrollBar( ).sliderPosition() self.metadataDlg.VManager.setRowCount(0) except: None def saveInfoToJson(self): """ Save video Info to json """ if not self.KillAllProcessors(): return out_json, _ = QFileDialog.getSaveFileName(self, "Save File", "", "Json Files (*.json)") if out_json == "": return try: self.VPProbeToJson = Converter() self.VPTProbeToJson = QThread() self.VPProbeToJson.moveToThread(self.VPTProbeToJson) self.VPProbeToJson.finished.connect(self.QThreadFinished) self.VPProbeToJson.error.connect(self.QThreadError) self.VPProbeToJson.progress.connect( self.progressBarProcessor.setValue) self.VPTProbeToJson.start(QThread.LowPriority) QMetaObject.invokeMethod(self.VPProbeToJson, 'probeToJson', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, out_json)) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Error saving Json")) self.QThreadFinished("probeToJson", "Closing ProbeToJson") def showVideoInfo(self): ''' Show default probe info ''' try: self.VPProbe = Converter() self.VPTProbe = QThread() self.VPProbe.moveToThread(self.VPTProbe) self.VPProbe.finishedJson.connect(self.QThreadFinished) self.VPProbe.error.connect(self.QThreadError) self.VPProbe.progress.connect(self.progressBarProcessor.setValue) self.VPTProbe.start(QThread.LowPriority) QMetaObject.invokeMethod(self.VPProbe, 'probeShow', Qt.QueuedConnection, Q_ARG(str, self.fileName)) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Error Info Show")) self.QThreadFinished("probeShow", "Closing Probe") return def state(self): ''' Return Current State ''' return self.playerState def setCurrentState(self, state): ''' Set Current State ''' if state != self.playerState: self.playerState = state if state == QMediaPlayer.StoppedState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) return def showColorDialog(self): ''' Show Color dialog ''' self.ColorDialog = ColorDialog(parent=self) self.ColorDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) # Fail if not uncheked self.actionMagnifying_glass.setChecked(False) self.actionZoom_Rectangle.setChecked(False) self.ColorDialog.exec_() return def createMosaic(self, value): ''' Function for create Video Mosaic ''' home = os.path.expanduser("~") qgsu.createFolderByName(home, "QGIS_FMV") homefmv = os.path.join(home, "QGIS_FMV") root, ext = os.path.splitext(os.path.basename(self.fileName)) qgsu.createFolderByName(homefmv, root) self.createingMosaic = value # Create Group CreateGroupByName() return def contextMenuRequested(self, point): ''' Context Menu Video ''' menu = QMenu() # actionColors = menu.addAction( # QCoreApplication.translate("QgsFmvPlayer", "Color Options")) # actionColors.setShortcut("Ctrl+May+C") # actionColors.triggered.connect(self.showColorDialog) actionMute = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Mute/Unmute")) actionMute.setShortcut("Ctrl+May+U") actionMute.triggered.connect(self.setMuted) menu.addSeparator() actionAllFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract All Frames")) actionAllFrames.setShortcut("Ctrl+May+A") actionAllFrames.triggered.connect(self.ExtractAllFrames) actionCurrentFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract Current Frame")) actionCurrentFrames.setShortcut("Ctrl+May+Q") actionCurrentFrames.triggered.connect(self.ExtractCurrentFrame) menu.addSeparator() actionShowMetadata = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Show Metadata")) actionShowMetadata.setShortcut("Ctrl+May+M") actionShowMetadata.triggered.connect(self.OpenQgsFmvMetadata) menu.exec_(self.mapToGlobal(point)) # Start Snnipet FILTERS def grayFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetGray(value) self.videoWidget.UpdateSurface() return def edgeFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetEdgeDetection(value) self.videoWidget.UpdateSurface() return def invertColorFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetInvertColor(value) self.videoWidget.UpdateSurface() return def autoContrastFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetAutoContrastFilter(value) self.videoWidget.UpdateSurface() return def monoFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetMonoFilter(value) self.videoWidget.UpdateSurface() return def magnifier(self, value): self.UncheckUtils(self.sender(), value) self.videoWidget.SetMagnifier(value) self.videoWidget.UpdateSurface() return def zoomRect(self, value): self.UncheckUtils(self.sender(), value) self.videoWidget.SetZoomRect(value) self.videoWidget.UpdateSurface() return def UncheckUtils(self, sender, value): # p = self.player.position() # self.player.setVideoOutput( # self.videoWidget.videoSurface()) # Custom surface # self.player.setPosition(p) QApplication.processEvents() name = sender.objectName() self.actionMagnifying_glass.setChecked( True if name == "actionMagnifying_glass" else False) self.actionZoom_Rectangle.setChecked(True if name == "actionZoom_Rectangle" else False) sender.setChecked(value) return def UncheckFilters(self, sender, value): # p = self.player.position() # self.player.setVideoOutput( # self.videoWidget.videoSurface()) # Custom surface # self.player.setPosition(p) # QApplication.processEvents() name = sender.objectName() self.actionGray.setChecked(True if name == "actionGray" else False) self.actionInvert_Color.setChecked(True if name == "actionInvert_Color" else False) self.actionMono_Filter.setChecked(True if name == "actionMono_Filter" else False) self.actionCanny_edge_detection.setChecked( True if name == "actionCanny_edge_detection" else False) self.actionAuto_Contrast_Filter.setChecked( True if name == "actionAuto_Contrast_Filter" else False) self.videoWidget.SetGray(True if name == "actionGray" else False) self.videoWidget.SetEdgeDetection( True if name == "actionCanny_edge_detection" else False) self.videoWidget.SetInvertColor(True if name == "actionInvert_Color" else False) self.videoWidget.SetMonoFilter(True if name == "actionMono_Filter" else False) self.videoWidget.SetAutoContrastFilter( True if name == "actionAuto_Contrast_Filter" else False) sender.setChecked(value) return # End Snnipet FILTERS def isMuted(self): ''' Is muted video property''' return self.playerMuted def setMuted(self): ''' Muted video ''' if self.player.isMuted(): self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) self.player.setMuted(False) self.volumeSlider.setEnabled(True) else: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) self.player.setMuted(True) self.volumeSlider.setEnabled(False) return def stop(self): ''' Stop video''' self.player.stop() self.videoWidget.update() return def volume(self): ''' Volume Slider ''' return self.volumeSlider.value() def setVolume(self, volume): ''' Tooltip and set value''' self.player.setVolume(volume) self.showVolumeTip(volume) if 0 < volume <= 30: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_30.png")) elif 30 < volume <= 60: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_60.png")) elif 60 < volume <= 100: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) elif volume == 0: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) def EndMedia(self): ''' Button end video position ''' if self.player.isVideoAvailable(): self.player.setPosition(self.player.duration()) self.videoWidget.update() return def StartMedia(self): ''' Button start video position ''' if self.player.isVideoAvailable(): self.player.setPosition(0) self.videoWidget.update() return def forwardMedia(self): ''' Button forward Video ''' forwardTime = int(self.player.position()) + 10 * 1000 if forwardTime > int(self.player.duration()): forwardTime = int(self.player.duration()) self.player.setPosition(forwardTime) def rewindMedia(self): ''' Button rewind Video ''' rewindTime = int(self.player.position()) - 10 * 1000 if rewindTime < 0: rewindTime = 0 self.player.setPosition(rewindTime) def AutoRepeat(self, checked): ''' Button AutoRepeat Video ''' if checked: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) return def showVolumeTip(self, _): ''' Volume Slider Tooltip Trick ''' self.style = self.volumeSlider.style() self.opt = QStyleOptionSlider() self.volumeSlider.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.volumeSlider.mapToGlobal(pos_local) QToolTip.showText(pos_global, str(self.volumeSlider.value()) + " %", self) def showMoveTip(self, currentInfo): ''' Player Silder Move Tooptip Trick ''' self.style = self.sliderDuration.style() self.opt = QStyleOptionSlider() self.sliderDuration.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.sliderDuration.mapToGlobal(pos_local) tStr = _seconds_to_time(currentInfo) QToolTip.showText(pos_global, tStr, self) def durationChanged(self, duration): ''' Duration video change signal ''' duration /= 1000 self.duration = duration self.sliderDuration.setMaximum(duration) def positionChanged(self, progress): ''' Current Video position change ''' progress /= 1000 if not self.sliderDuration.isSliderDown(): self.sliderDuration.setValue(progress) self.updateDurationInfo(progress) def updateDurationInfo(self, currentInfo): ''' Update labels duration Info and CallBack Metadata ''' duration = self.duration self.currentInfo = currentInfo if currentInfo or duration: totalTime = _seconds_to_time(duration) currentTime = _seconds_to_time(currentInfo) tStr = currentTime + " / " + totalTime nextTime = currentInfo + self.pass_time currentTimeInfo = _seconds_to_time_frac(currentInfo) nextTimeInfo = _seconds_to_time_frac(nextTime) # Metadata CallBack self.callBackMetadata(currentTimeInfo, nextTimeInfo) else: tStr = "" self.labelDuration.setText(tStr) def handleCursor(self, status): ''' Change cursor ''' if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def statusChanged(self, status): ''' Signal Status video change ''' self.handleCursor(status) if status == QMediaPlayer.LoadingMedia: self.videoAvailableChanged(False) elif status == QMediaPlayer.StalledMedia: self.videoAvailableChanged(False) if status == QMediaPlayer.EndOfMedia: self.videoAvailableChanged(True) elif status == QMediaPlayer.InvalidMedia: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", self.player.errorString()), level=QGis.Warning) self.videoAvailableChanged(False) else: self.videoAvailableChanged(True) def playFile(self, videoPath): ''' Play file from path ''' try: RemoveVideoLayers() RemoveGroupByName() self.fileName = videoPath self.playlist = QMediaPlaylist() url = QUrl.fromLocalFile(videoPath) self.playlist.addMedia(QMediaContent(url)) self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.player.setPlaylist(self.playlist) self.setWindowTitle("Playing : " + os.path.basename(os.path.normpath(videoPath))) if self.HasMetadata(videoPath): CreateVideoLayers() self.clearMetadata() self.lb_cursor_coord.setText( "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>" + "<span style='font-size:9pt; font-weight:normal;'>Null</span>" + "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>" + "<span style='font-size:9pt; font-weight:normal;'>Null</span>" ) else: self.btn_GeoReferencing.setEnabled(False) self.HasFileAudio = True if not self.HasAudio(videoPath): self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) self.HasFileAudio = False self.playClicked(True) except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", 'Open Video File : '), str(e), level=QGis.Warning) def ReciconUpdate(self, frame): self.btn_Rec.setIcon(QIcon(self.RecGIF.currentPixmap())) def RecordVideo(self, value): ''' Cut Video ''' currentTime = _seconds_to_time(self.currentInfo) if value is False: self.endRecord = currentTime _, file_extension = os.path.splitext(self.fileName) out, _ = QFileDialog.getSaveFileName(self, "Save As", "", file_extension) if not out: self.RecGIF.frameChanged.disconnect(self.ReciconUpdate) self.RecGIF.stop() self.btn_Rec.setIcon(QIcon(":/imgFMV/images/record.png")) return False lfn = out.lower() if not lfn.endswith((file_extension)): out += file_extension p = _spawn([ '-i', self.fileName, '-ss', self.startRecord, '-to', self.endRecord, '-c', 'copy', out ]) p.communicate() qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Save file succesfully!")) self.RecGIF.frameChanged.disconnect(self.ReciconUpdate) self.RecGIF.stop() self.btn_Rec.setIcon(QIcon(":/imgFMV/images/record.png")) else: self.startRecord = currentTime self.RecGIF.frameChanged.connect(self.ReciconUpdate) self.RecGIF.start() return def videoAvailableChanged(self, available): ''' Buttons for video available ''' # self.btn_Color.setEnabled(available) self.btn_CaptureFrame.setEnabled(available) self.gb_PlayerControls.setEnabled(available) return def toggleGroup(self, state): ''' Toggle GroupBox ''' sender = self.sender() if state: sender.setFixedHeight(sender.sizeHint().height()) else: sender.setFixedHeight(15) def playClicked(self, state): ''' Stop and Play video ''' if self.playerState in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.btn_play.setIcon(QIcon(":/imgFMV/images/pause.png")) self.player.play() elif self.playerState == QMediaPlayer.PlayingState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) self.player.pause() def seek(self, seconds): '''Slider Move''' self.player.setPosition(seconds * 1000) self.showMoveTip(seconds) def convertVideo(self): '''Convert Video To Other Format ''' if not self.KillAllProcessors(): return sel = "mp4 Files (*.mp4)" out, _ = QFileDialog.getSaveFileName( self, "Save Video as...", None, "ogg files (*.ogg);;avi Files (*.avi);;mkv Files (*.mkv);;webm Files (*.webm);;flv Files (*.flv);;mov Files (*.mov);;mp4 Files (*.mp4);;mpg Files (*.mpg);;mp3 Files (*.mp3)", sel) if not out: return False lfn = out.lower() if not lfn.endswith(('.ogg', '.avi', '.mkv', '.webm', '.flv', '.mov', '.mp4', '.mp3', '.mpg')): # The default. out += '.mp4' try: self.VPConverter = Converter() self.VPTConverter = QThread() self.VPConverter.moveToThread(self.VPTConverter) self.VPConverter.finished.connect(self.QThreadFinished) self.VPConverter.error.connect(self.QThreadError) self.VPConverter.progress.connect( self.progressBarProcessor.setValue) self.VPTConverter.start(QThread.LowPriority) # TODO : Make Correct format Conversion and embebed metadata info = self.VPConverter.probeInfo(self.fileName) if info is not None: if self.HasFileAudio: audio_codec = info.audio.codec audio_samplerate = info.audio.audio_samplerate audio_channels = info.audio.audio_channels video_codec = info.video.codec video_width = info.video.video_width video_height = info.video.video_height video_fps = info.video.video_fps _, out_ext = os.path.splitext(out) if self.HasFileAudio: options = { 'format': out_ext[1:], 'audio': { 'codec': audio_codec, 'samplerate': audio_samplerate, 'channels': audio_channels }, 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } else: options = { 'format': out_ext[1:], 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } QMetaObject.invokeMethod(self.VPConverter, 'convert', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, out), Q_ARG(dict, options), Q_ARG(bool, False)) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Error converting video ")) self.QThreadFinished("convert", "Closing convert") def ShowPlot(self, bitrate_data, frame_count, output=None): ''' Show plot,because show not work using threading ''' matplot.figure().canvas.set_window_title(self.fileName) matplot.title("Stream Bitrate vs Time") matplot.xlabel("Time (sec)") matplot.ylabel("Frame Bitrate (kbit/s)") matplot.grid(True) # map frame type to color frame_type_color = { # audio 'A': 'yellow', # video 'I': 'red', 'P': 'green', 'B': 'blue' } global_peak_bitrate = 0.0 global_mean_bitrate = 0.0 # render charts in order of expected decreasing size for frame_type in ['I', 'P', 'B', 'A']: # skip frame type if missing if frame_type not in bitrate_data: continue # convert list of tuples to numpy 2d array frame_list = bitrate_data[frame_type] frame_array = numpy.array(frame_list) # update global peak bitrate peak_bitrate = frame_array.max(0)[1] if peak_bitrate > global_peak_bitrate: global_peak_bitrate = peak_bitrate # update global mean bitrate (using piecewise mean) mean_bitrate = frame_array.mean(0)[1] global_mean_bitrate += mean_bitrate * \ (len(frame_list) / frame_count) # plot chart using gnuplot-like impulses matplot.vlines(frame_array[:, 0], [0], frame_array[:, 1], color=frame_type_color[frame_type], label="{} Frames".format(frame_type)) self.progressBarProcessor.setValue(90) # calculate peak line position (left 15%, above line) peak_text_x = matplot.xlim()[1] * 0.15 peak_text_y = global_peak_bitrate + \ ((matplot.ylim()[1] - matplot.ylim()[0]) * 0.015) peak_text = "peak ({:.0f})".format(global_peak_bitrate) # draw peak as think black line w/ text matplot.axhline(global_peak_bitrate, linewidth=2, color='black') matplot.text(peak_text_x, peak_text_y, peak_text, horizontalalignment='center', fontweight='bold', color='black') # calculate mean line position (right 85%, above line) mean_text_x = matplot.xlim()[1] * 0.85 mean_text_y = global_mean_bitrate + \ ((matplot.ylim()[1] - matplot.ylim()[0]) * 0.015) mean_text = "mean ({:.0f})".format(global_mean_bitrate) # draw mean as think black line w/ text matplot.axhline(global_mean_bitrate, linewidth=2, color='black') matplot.text(mean_text_x, mean_text_y, mean_text, horizontalalignment='center', fontweight='bold', color='black') matplot.legend() if output != "": matplot.savefig(output) else: matplot.show() self.progressBarProcessor.setValue(100) def CreateBitratePlot(self): ''' Create video Plot Bitrate Thread ''' if not self.KillAllProcessors(): return try: self.VPBitratePlot = CreatePlotsBitrate() self.VPTBitratePlot = QThread() self.VPBitratePlot.moveToThread(self.VPTBitratePlot) self.VPBitratePlot.finished.connect(self.QThreadFinished) self.VPBitratePlot.return_fig.connect(self.ShowPlot) self.VPBitratePlot.error.connect(self.QThreadError) self.VPBitratePlot.progress.connect( self.progressBarProcessor.setValue) self.VPTBitratePlot.start(QThread.LowPriority) sender = self.sender().objectName() if sender == "actionAudio": QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, None), Q_ARG(str, 'audio')) elif sender == "actionVideo": QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, None), Q_ARG(str, 'video')) elif sender == "actionSave_Audio": selfilter = "Portable Network Graphics (*.png)" fileaudio, _ = QFileDialog.getSaveFileName( self, "Save Audio Bitrate Plot", "", "EPS Encapsulated Postscript (*.eps);;" "PGF code for LaTex (*.pgf);;" "Portable document format(*pdf);;" "Portable Network Graphics (*.png);;" "Postscript (*.ps);;" "Raw RGBA bitmap (*.raw*.rgba);;" "Scalable vector graphics (*.svg*.svgz)", selfilter) if fileaudio == "": return QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, fileaudio), Q_ARG(str, 'audio')) elif sender == "actionSave_Video": selfilter = "Portable Network Graphics (*.png)" filevideo, _ = QFileDialog.getSaveFileName( self, "Save Video Bitrate Plot", "", "EPS Encapsulated Postscript (*.eps);;" "PGF code for LaTex (*.pgf);;" "Portable document format(*pdf);;" "Portable Network Graphics (*.png);;" "Postscript (*.ps);;" "Raw RGBA bitmap (*.raw*.rgba);;" "Scalable vector graphics (*.svg*.svgz)", selfilter) if filevideo == "": return QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, filevideo), Q_ARG(str, 'video')) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Failed creating Plot Bitrate")) def ExtractAllFrames(self): """ Extract All Video Frames Thread """ if not self.KillAllProcessors(): return options = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly directory = QFileDialog.getExistingDirectory( self, QCoreApplication.translate("QgsFmvPlayer", "Save images"), '', options=options) if directory: self.VPExtractFrames = ExtractFramesProcessor() self.VPTExtractAllFrames = QThread() self.VPExtractFrames.moveToThread(self.VPTExtractAllFrames) self.VPExtractFrames.finished.connect(self.QThreadFinished) self.VPExtractFrames.error.connect(self.QThreadError) self.VPExtractFrames.progress.connect( self.progressBarProcessor.setValue) self.VPTExtractAllFrames.start(QThread.LowPriority) QMetaObject.invokeMethod(self.VPExtractFrames, 'ExtractFrames', Qt.QueuedConnection, Q_ARG(str, directory), Q_ARG(str, self.fileName)) return def ExtractCurrentFrame(self): """ Extract Current Frame Thread """ image = self.videoWidget.GetCurrentFrame() out_image, _ = QFileDialog.getSaveFileName( self, "Save Current Frame", "", "Image File (*.png *.jpg *.bmp *.tiff)") if out_image == "": return if out_image: t = threading.Thread(target=self.SaveCapture, args=( image, out_image, )) t.start() return def SaveCapture(self, image, output): ''' Save Current Image ''' image.save(output) QApplication.processEvents() return def QThreadFinished(self, process, msg, outjson=None): ''' Finish Threads ''' if process == "ExtractFramesProcessor": self.VPExtractFrames.deleteLater() self.VPTExtractAllFrames.terminate() self.VPTExtractAllFrames.deleteLater() elif process == "CreatePlotsBitrate": self.VPBitratePlot.deleteLater() self.VPTBitratePlot.terminate() self.VPTBitratePlot.deleteLater() elif process == "convert": self.VPConverter.deleteLater() self.VPTConverter.terminate() self.VPTConverter.deleteLater() elif process == "probeToJson": self.VPProbeToJson.deleteLater() self.VPTProbeToJson.terminate() self.VPTProbeToJson.deleteLater() elif process == "probeShow": self.VPProbe.deleteLater() self.VPTProbe.terminate() self.VPTProbe.deleteLater() self.showVideoInfoDialog(outjson) QApplication.processEvents() self.progressBarProcessor.setValue(0) return def QThreadError(self, processor, e, exception_string): """ Threads Errors""" qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", processor), 'Failed!\n'.format(exception_string), level=QGis.Warning) self.QThreadFinished(processor, "Closing Processor") return def OpenQgsFmvMetadata(self): """ Open Metadata Dock """ if self.metadataDlg is None: self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.show() else: self.metadataDlg.show() return def KillAllProcessors(self): """Kill All Processors""" """ Extract all frames Processors """ try: if self.VPTExtractAllFrames.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("ExtractFramesProcessor", "Closing Extract Frames Processor") else: return False except: None """ Bitrates Processors""" try: if self.VPTBitratePlot.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("CreatePlotsBitrate", "Closing Plot Bitrate") else: return False except: None """ Converter Processors """ try: if self.VPTConverter.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("convert", "Closing convert") else: return False except: None """ probeToJson Processors """ try: if self.VPTProbeToJson.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("probeToJson", "Closing Info to Json") else: return False except: None """ probeShow Processors """ try: if self.VPTProbe.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("probeShow", "Closing Show Video Info") else: return False except: None return True def showVideoInfoDialog(self, outjson): """ Show Video Information Dialog """ view = QTreeView() model = QJsonModel() view.setModel(model) model.loadJsonFromConsole(outjson) self.VideoInfoDialog = QDialog(self) self.VideoInfoDialog.setWindowTitle("Video Information : " + self.fileName) self.VideoInfoDialog.setWindowIcon( QIcon(":/imgFMV/images/video_information.png")) self.verticalLayout = QVBoxLayout(self.VideoInfoDialog) self.verticalLayout.addWidget(view) view.expandAll() view.header().setSectionResizeMode(QHeaderView.ResizeToContents) self.VideoInfoDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) self.VideoInfoDialog.setObjectName("VideoInfoDialog") self.VideoInfoDialog.resize(500, 400) self.VideoInfoDialog.show() def closeEvent(self, evt): """ Close Event """ if self.KillAllProcessors() is False: evt.ignore() return self.player.stop() self.parent._PlayerDlg = None self.parent.ToggleActiveFromTitle() RemoveVideoLayers() RemoveGroupByName() # Restore Filters State self.videoWidget.RestoreFilters() # QApplication.processEvents() del self.player